diff --git a/eth/gasprice/gasprice.go b/eth/gasprice/gasprice.go index e83a6c5a8..91041a9cb 100644 --- a/eth/gasprice/gasprice.go +++ b/eth/gasprice/gasprice.go @@ -18,6 +18,7 @@ package gasprice import ( "context" + "errors" "math/big" "sort" "sync" @@ -33,6 +34,9 @@ var ( maxPrice = big.NewInt(500 * params.GWei) maxPremium = big.NewInt(500 * params.GWei) maxFeeCap = big.NewInt(1000 * params.GWei) + + errEIP1559IsFinalized = errors.New("past EIP1559 finalization, GasPrice cannot be set") + errEIP1559IsNotActivated = errors.New("before EIP1559 activation, GasPremium and FeeCap cannot be set") ) type Config struct { @@ -92,6 +96,9 @@ func (gpo *Oracle) SuggestPrice(ctx context.Context) (*big.Int, error) { gpo.cacheLock.RUnlock() head, _ := gpo.backend.HeaderByNumber(ctx, rpc.LatestBlockNumber) + if gpo.backend.ChainConfig().IsEIP1559Finalized(head.Number) { + return nil, errEIP1559IsFinalized + } headHash := head.Hash() if headHash == lastHead { return lastPrice, nil @@ -166,6 +173,9 @@ func (gpo *Oracle) SuggestPremium(ctx context.Context) (*big.Int, error) { gpo.cacheLock.RUnlock() head, _ := gpo.backend.HeaderByNumber(ctx, rpc.LatestBlockNumber) + if !gpo.backend.ChainConfig().IsEIP1559(head.Number) { + return nil, errEIP1559IsNotActivated + } headHash := head.Hash() if headHash == lastHead { return lastPremium, nil @@ -240,6 +250,9 @@ func (gpo *Oracle) SuggestCap(ctx context.Context) (*big.Int, error) { gpo.cacheLock.RUnlock() head, _ := gpo.backend.HeaderByNumber(ctx, rpc.LatestBlockNumber) + if !gpo.backend.ChainConfig().IsEIP1559(head.Number) { + return nil, errEIP1559IsNotActivated + } headHash := head.Hash() if headHash == lastHead { return lastCap, nil @@ -321,34 +334,52 @@ type getBlockCapsResult struct { err error } -type transactionsByGasPrice []*types.Transaction +type transactionsByGasPrice struct { + txs []*types.Transaction + baseFee *big.Int +} -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 { - iPrice := t[i].GasPrice() - jPrice := t[j].GasPrice() +func (t *transactionsByGasPrice) Len() int { return len(t.txs) } +func (t *transactionsByGasPrice) Swap(i, j int) { t.txs[i], t.txs[j] = t.txs[j], t.txs[i] } +func (t *transactionsByGasPrice) Less(i, j int) bool { + iPrice := t.txs[i].GasPrice() + jPrice := t.txs[j].GasPrice() if iPrice == nil { - iPrice = big.NewInt(0) + iPrice = new(big.Int).Add(t.baseFee, t.txs[i].GasPremium()) + if iPrice.Cmp(t.txs[i].FeeCap()) > 0 { + iPrice.Set(t.txs[i].FeeCap()) + } } if jPrice == nil { - jPrice = big.NewInt(0) + jPrice = new(big.Int).Add(t.baseFee, t.txs[j].GasPremium()) + if jPrice.Cmp(t.txs[j].FeeCap()) > 0 { + jPrice.Set(t.txs[j].FeeCap()) + } } return iPrice.Cmp(jPrice) < 0 } -type transactionsByGasPremium []*types.Transaction +type transactionsByGasPremium struct { + txs []*types.Transaction + baseFee *big.Int +} -func (t transactionsByGasPremium) Len() int { return len(t) } -func (t transactionsByGasPremium) Swap(i, j int) { t[i], t[j] = t[j], t[i] } -func (t transactionsByGasPremium) Less(i, j int) bool { - iPremium := t[i].GasPremium() - jPremium := t[j].GasPremium() +func (t *transactionsByGasPremium) Len() int { return len(t.txs) } +func (t *transactionsByGasPremium) Swap(i, j int) { t.txs[i], t.txs[j] = t.txs[j], t.txs[i] } +func (t *transactionsByGasPremium) Less(i, j int) bool { + iPremium := t.txs[i].GasPremium() + jPremium := t.txs[j].GasPremium() if iPremium == nil { - iPremium = big.NewInt(0) + iPremium = new(big.Int).Sub(t.txs[i].GasPrice(), t.baseFee) + if iPremium.Cmp(common.Big0) < 0 { + iPremium.Set(common.Big0) + } } if jPremium == nil { - jPremium = big.NewInt(0) + jPremium = new(big.Int).Sub(t.txs[j].GasPrice(), t.baseFee) + if jPremium.Cmp(common.Big0) < 0 { + jPremium.Set(common.Big0) + } } return iPremium.Cmp(jPremium) < 0 } @@ -361,10 +392,10 @@ func (t transactionsByFeeCap) Less(i, j int) bool { iCap := t[i].FeeCap() jCap := t[j].FeeCap() if iCap == nil { - iCap = big.NewInt(0) + iCap = t[i].GasPrice() } if jCap == nil { - jCap = big.NewInt(0) + jCap = t[j].GasPrice() } return iCap.Cmp(jCap) < 0 } @@ -379,14 +410,23 @@ func (gpo *Oracle) getBlockPrices(ctx context.Context, signer types.Signer, bloc } blockTxs := block.Transactions() - txs := make([]*types.Transaction, len(blockTxs)) - copy(txs, blockTxs) - sort.Sort(transactionsByGasPrice(txs)) + txs := new(transactionsByGasPrice) + txs.txs = make([]*types.Transaction, len(blockTxs)) + copy(txs.txs, blockTxs) + txs.baseFee = block.BaseFee() + sort.Sort(txs) - for _, tx := range txs { + for _, tx := range txs.txs { sender, err := types.Sender(signer, tx) if err == nil && sender != block.Coinbase() { - ch <- getBlockPricesResult{tx.GasPrice(), nil} + price := tx.GasPrice() + if price == nil { + price = new(big.Int).Add(block.BaseFee(), tx.GasPremium()) + if price.Cmp(tx.FeeCap()) > 0 { + price.Set(tx.FeeCap()) + } + } + ch <- getBlockPricesResult{price, nil} return } } @@ -403,14 +443,23 @@ func (gpo *Oracle) getBlockPremiums(ctx context.Context, signer types.Signer, bl } blockTxs := block.Transactions() - txs := make([]*types.Transaction, len(blockTxs)) - copy(txs, blockTxs) - sort.Sort(transactionsByGasPremium(txs)) + txs := new(transactionsByGasPremium) + txs.txs = make([]*types.Transaction, len(blockTxs)) + copy(txs.txs, blockTxs) + txs.baseFee = block.BaseFee() + sort.Sort(txs) - for _, tx := range txs { + for _, tx := range txs.txs { sender, err := types.Sender(signer, tx) if err == nil && sender != block.Coinbase() { - ch <- getBlockPremiumsResult{tx.GasPremium(), nil} + premium := tx.GasPremium() + if premium == nil { + premium = new(big.Int).Sub(tx.GasPrice(), block.BaseFee()) + if premium.Cmp(common.Big0) < 0 { + premium.Set(common.Big0) + } + } + ch <- getBlockPremiumsResult{premium, nil} return } } @@ -434,7 +483,11 @@ func (gpo *Oracle) getBlockCaps(ctx context.Context, signer types.Signer, blockN for _, tx := range txs { sender, err := types.Sender(signer, tx) if err == nil && sender != block.Coinbase() { - ch <- getBlockCapsResult{tx.FeeCap(), nil} + cap := tx.FeeCap() + if cap == nil { + cap = tx.GasPrice() + } + ch <- getBlockCapsResult{cap, nil} return } } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index bac46f043..eb4886131 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -395,8 +395,8 @@ func (s *PrivateAccountAPI) SignTransaction(ctx context.Context, args SendTxArgs if args.Gas == nil { return nil, fmt.Errorf("gas not specified") } - if args.GasPrice == nil { - return nil, fmt.Errorf("gasPrice not specified") + if args.GasPrice == nil && (args.GasPremium == nil || args.FeeCap == nil) { + return nil, fmt.Errorf("gasPrice or gasPremium+feeCap not specified") } if args.Nonce == nil { return nil, fmt.Errorf("nonce not specified") diff --git a/les/client.go b/les/client.go index 8c1bd55b3..b2a5a5f54 100644 --- a/les/client.go +++ b/les/client.go @@ -20,6 +20,7 @@ package les import ( "fmt" "time" + "math/big" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -161,6 +162,20 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) { if gpoParams.DefaultGasPrice == nil { gpoParams.DefaultGasPrice = config.Miner.GasPrice } + if gpoParams.DefaultFeeCap == nil { + gpoParams.DefaultFeeCap = config.Miner.GasPrice + } + if gpoParams.DefaultGasPremium == nil { + baseFee := leth.blockchain.CurrentHeader().BaseFee + if baseFee == nil { + baseFee = new(big.Int).SetUint64(params.EIP1559InitialBaseFee) + } + gasPremium := new(big.Int).Sub(config.Miner.GasPrice, baseFee) + if gasPremium.Cmp(big.NewInt(0)) < 0 { + gasPremium = big.NewInt(0) + } + gpoParams.DefaultGasPremium = gasPremium + } leth.ApiBackend.gpo = gasprice.NewOracle(leth.ApiBackend, gpoParams) leth.handler = newClientHandler(config.UltraLightServers, config.UltraLightFraction, checkpoint, leth)