internal/ethapi: cap txfee for SignTransaction and Resend (#21231)

This commit is contained in:
gary rong 2020-07-13 18:45:39 +08:00 committed by GitHub
parent 6cf6e1d753
commit 4edbc1f2bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -406,6 +406,10 @@ func (s *PrivateAccountAPI) SignTransaction(ctx context.Context, args SendTxArgs
if args.Nonce == nil { if args.Nonce == nil {
return nil, fmt.Errorf("nonce not specified") return nil, fmt.Errorf("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) signed, err := s.signTransaction(ctx, &args, passwd)
if err != nil { if err != nil {
log.Warn("Failed transaction sign attempt", "from", args.From, "to", args.To, "value", args.Value.ToInt(), "err", err) log.Warn("Failed transaction sign attempt", "from", args.From, "to", args.To, "value", args.Value.ToInt(), "err", err)
@ -1545,10 +1549,8 @@ func (args *SendTxArgs) toTransaction() *types.Transaction {
func SubmitTransaction(ctx context.Context, b Backend, tx *types.Transaction) (common.Hash, error) { func SubmitTransaction(ctx context.Context, b Backend, tx *types.Transaction) (common.Hash, error) {
// If the transaction fee cap is already specified, ensure the // If the transaction fee cap is already specified, ensure the
// fee of the given transaction is _reasonable_. // 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))) if err := checkTxFee(tx.GasPrice(), tx.Gas(), b.RPCTxFeeCap()); err != nil {
feeFloat, _ := feeEth.Float64() return common.Hash{}, err
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 := b.SendTx(ctx, tx); err != nil { if err := b.SendTx(ctx, tx); err != nil {
return common.Hash{}, err return common.Hash{}, err
@ -1672,6 +1674,10 @@ func (s *PublicTransactionPoolAPI) SignTransaction(ctx context.Context, args Sen
if err := args.setDefaults(ctx, s.b); err != nil { if err := args.setDefaults(ctx, s.b); err != nil {
return nil, err 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()) tx, err := s.sign(args.From, args.toTransaction())
if err != nil { if err != nil {
return nil, err return nil, err
@ -1720,11 +1726,24 @@ func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, sendArgs SendTxAr
return common.Hash{}, err return common.Hash{}, err
} }
matchTx := sendArgs.toTransaction() 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() pending, err := s.b.GetPoolTransactions()
if err != nil { if err != nil {
return common.Hash{}, err return common.Hash{}, err
} }
for _, p := range pending { for _, p := range pending {
var signer types.Signer = types.HomesteadSigner{} var signer types.Signer = types.HomesteadSigner{}
if p.Protected() { if p.Protected() {
@ -1901,3 +1920,18 @@ func (s *PublicNetAPI) PeerCount() hexutil.Uint {
func (s *PublicNetAPI) Version() string { func (s *PublicNetAPI) Version() string {
return fmt.Sprintf("%d", s.networkVersion) 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
}