From 341ca00b16dce10b12195ee7b4fa89d4827dcd75 Mon Sep 17 00:00:00 2001 From: Daniel Liu Date: Thu, 13 Jun 2024 12:28:33 +0800 Subject: [PATCH] internal/ethapi: cap txfee for SignTransaction and Resend (#21231) --- internal/ethapi/api.go | 57 ++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index d94ec30f34b5..fad8f0cb513c 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -412,6 +412,10 @@ func (s *PrivateAccountAPI) SignTransaction(ctx context.Context, args SendTxArgs if args.Nonce == nil { return nil, errors.New("nonce not specified") } + // Before actually sign the transaction, ensure the transaction fee is reasonable. + if err := checkTxFee(args.GasPrice.ToInt(), uint64(*args.Gas), s.b.RPCTxFeeCap()); err != nil { + return nil, err + } signed, err := s.signTransaction(ctx, args, passwd) if err != nil { log.Warn("Failed transaction sign attempt", "from", args.From, "to", args.To, "value", args.Value.ToInt(), "err", err) @@ -2375,10 +2379,8 @@ func SubmitTransaction(ctx context.Context, b Backend, tx *types.Transaction) (c // If the transaction fee cap is already specified, ensure the // fee of the given transaction is _reasonable_. - feeEth := new(big.Float).Quo(new(big.Float).SetInt(new(big.Int).Mul(tx.GasPrice(), new(big.Int).SetUint64(tx.Gas()))), new(big.Float).SetInt(big.NewInt(params.Ether))) - feeFloat, _ := feeEth.Float64() - if b.RPCTxFeeCap() != 0 && feeFloat > b.RPCTxFeeCap() { - return common.Hash{}, fmt.Errorf("tx fee (%.2f ether) exceeds the configured cap (%.2f ether)", feeFloat, b.RPCTxFeeCap()) + if err := checkTxFee(tx.GasPrice(), tx.Gas(), b.RPCTxFeeCap()); err != nil { + return common.Hash{}, err } if err := b.SendTx(ctx, tx); err != nil { return common.Hash{}, err @@ -3367,6 +3369,10 @@ func (s *PublicTransactionPoolAPI) SignTransaction(ctx context.Context, args Sen if err := args.setDefaults(ctx, s.b); err != nil { return nil, err } + // Before actually sign the transaction, ensure the transaction fee is reasonable. + if err := checkTxFee(args.GasPrice.ToInt(), uint64(*args.Gas), s.b.RPCTxFeeCap()); err != nil { + return nil, err + } tx, err := s.sign(args.From, args.toTransaction()) if err != nil { return nil, err @@ -3412,6 +3418,19 @@ func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, sendArgs SendTxAr } matchTx := sendArgs.toTransaction() + // Before replacing the old transaction, ensure the _new_ transaction fee is reasonable. + var price = matchTx.GasPrice() + if gasPrice != nil { + price = gasPrice.ToInt() + } + var gas = matchTx.Gas() + if gasLimit != nil { + gas = uint64(*gasLimit) + } + if err := checkTxFee(price, gas, s.b.RPCTxFeeCap()); err != nil { + return common.Hash{}, err + } + // Iterate the pending list for replacement pending, err := s.b.GetPoolTransactions() if err != nil { @@ -3561,6 +3580,21 @@ func (s *PublicNetAPI) Version() string { return fmt.Sprintf("%d", s.networkVersion) } +// checkTxFee is an internal function used to check whether the fee of +// the given transaction is _reasonable_(under the cap). +func checkTxFee(gasPrice *big.Int, gas uint64, cap float64) error { + // Short circuit if there is no cap for transaction fee at all. + if cap == 0 { + return nil + } + feeEth := new(big.Float).Quo(new(big.Float).SetInt(new(big.Int).Mul(gasPrice, new(big.Int).SetUint64(gas))), new(big.Float).SetInt(big.NewInt(params.Ether))) + feeFloat, _ := feeEth.Float64() + if feeFloat > cap { + return fmt.Errorf("tx fee (%.2f ether) exceeds the configured cap (%.2f ether)", feeFloat, cap) + } + return nil +} + func GetSignersFromBlocks(b Backend, blockNumber uint64, blockHash common.Hash, masternodes []common.Address) ([]common.Address, error) { var addrs []common.Address mapMN := map[common.Address]bool{} @@ -3661,18 +3695,3 @@ func (s *PublicBlockChainAPI) GetStakerROIMasternode(masternode common.Address) return 100.0 / float64(totalCap.Div(totalCap, voterRewardAYear).Uint64()) } - -// checkTxFee is an internal function used to check whether the fee of -// the given transaction is _reasonable_(under the cap). -func checkTxFee(gasPrice *big.Int, gas uint64, cap float64) error { - // Short circuit if there is no cap for transaction fee at all. - if cap == 0 { - return nil - } - feeEth := new(big.Float).Quo(new(big.Float).SetInt(new(big.Int).Mul(gasPrice, new(big.Int).SetUint64(gas))), new(big.Float).SetInt(big.NewInt(params.Ether))) - feeFloat, _ := feeEth.Float64() - if feeFloat > cap { - return fmt.Errorf("tx fee (%.2f ether) exceeds the configured cap (%.2f ether)", feeFloat, cap) - } - return nil -}