internal/ethapi, accounts/abi/bind: cap highest gas limit by account balance for 1559 fee parameters (#23309)
* internal/ethapi/api: cap highest gas limit by account balance for 1559 fee parameters * accounts/abi/bind: port gas limit cap for 1559 parameters to simulated backend * accounts/abi/bind: add test for 1559 gas estimates for the simulated backend * internal/ethapi/api: fix comment * accounts/abi/bind/backends, internal/ethapi: unify naming style Co-authored-by: Péter Szilágyi <peterke@gmail.com>
This commit is contained in:
		| @@ -488,8 +488,19 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMs | ||||
| 	} else { | ||||
| 		hi = b.pendingBlock.GasLimit() | ||||
| 	} | ||||
| 	// Normalize the max fee per gas the call is willing to spend. | ||||
| 	var feeCap *big.Int | ||||
| 	if call.GasPrice != nil && (call.GasFeeCap != nil || call.GasTipCap != nil) { | ||||
| 		return 0, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified") | ||||
| 	} else if call.GasPrice != nil { | ||||
| 		feeCap = call.GasPrice | ||||
| 	} else if call.GasFeeCap != nil { | ||||
| 		feeCap = call.GasFeeCap | ||||
| 	} else { | ||||
| 		feeCap = common.Big0 | ||||
| 	} | ||||
| 	// Recap the highest gas allowance with account's balance. | ||||
| 	if call.GasPrice != nil && call.GasPrice.BitLen() != 0 { | ||||
| 	if feeCap.BitLen() != 0 { | ||||
| 		balance := b.pendingState.GetBalance(call.From) // from can't be nil | ||||
| 		available := new(big.Int).Set(balance) | ||||
| 		if call.Value != nil { | ||||
| @@ -498,14 +509,14 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMs | ||||
| 			} | ||||
| 			available.Sub(available, call.Value) | ||||
| 		} | ||||
| 		allowance := new(big.Int).Div(available, call.GasPrice) | ||||
| 		allowance := new(big.Int).Div(available, feeCap) | ||||
| 		if allowance.IsUint64() && hi > allowance.Uint64() { | ||||
| 			transfer := call.Value | ||||
| 			if transfer == nil { | ||||
| 				transfer = new(big.Int) | ||||
| 			} | ||||
| 			log.Warn("Gas estimation capped by limited funds", "original", hi, "balance", balance, | ||||
| 				"sent", transfer, "gasprice", call.GasPrice, "fundable", allowance) | ||||
| 				"sent", transfer, "feecap", feeCap, "fundable", allowance) | ||||
| 			hi = allowance.Uint64() | ||||
| 		} | ||||
| 	} | ||||
|   | ||||
| @@ -580,6 +580,26 @@ func TestEstimateGasWithPrice(t *testing.T) { | ||||
| 			Value:    big.NewInt(100000000000), | ||||
| 			Data:     nil, | ||||
| 		}, 21000, errors.New("gas required exceeds allowance (10999)")}, // 10999=(2.2ether-1000wei)/(2e14) | ||||
|  | ||||
| 		{"EstimateEIP1559WithHighFees", ethereum.CallMsg{ | ||||
| 			From:      addr, | ||||
| 			To:        &addr, | ||||
| 			Gas:       0, | ||||
| 			GasFeeCap: big.NewInt(1e14), // maxgascost = 2.1ether | ||||
| 			GasTipCap: big.NewInt(1), | ||||
| 			Value:     big.NewInt(1e17), // the remaining balance for fee is 2.1ether | ||||
| 			Data:      nil, | ||||
| 		}, params.TxGas, nil}, | ||||
|  | ||||
| 		{"EstimateEIP1559WithSuperHighFees", ethereum.CallMsg{ | ||||
| 			From:      addr, | ||||
| 			To:        &addr, | ||||
| 			Gas:       0, | ||||
| 			GasFeeCap: big.NewInt(1e14), // maxgascost = 2.1ether | ||||
| 			GasTipCap: big.NewInt(1), | ||||
| 			Value:     big.NewInt(1e17 + 1), // the remaining balance for fee is 2.1ether | ||||
| 			Data:      nil, | ||||
| 		}, params.TxGas, errors.New("gas required exceeds allowance (20999)")}, // 20999=(2.2ether-0.1ether-1wei)/(1e14) | ||||
| 	} | ||||
| 	for i, c := range cases { | ||||
| 		got, err := sim.EstimateGas(context.Background(), c.message) | ||||
| @@ -592,6 +612,9 @@ func TestEstimateGasWithPrice(t *testing.T) { | ||||
| 			} | ||||
| 			continue | ||||
| 		} | ||||
| 		if c.expectError == nil && err != nil { | ||||
| 			t.Fatalf("test %d: didn't expect error, got %v", i, err) | ||||
| 		} | ||||
| 		if got != c.expect { | ||||
| 			t.Fatalf("test %d: gas estimation mismatch, want %d, got %d", i, c.expect, got) | ||||
| 		} | ||||
|   | ||||
| @@ -477,7 +477,7 @@ func (s *PrivateAccountAPI) SignTransaction(ctx context.Context, args Transactio | ||||
| 	if args.Nonce == nil { | ||||
| 		return nil, fmt.Errorf("nonce not specified") | ||||
| 	} | ||||
| 	// Before actually sign the transaction, ensure the transaction fee is reasonable. | ||||
| 	// Before actually signing the transaction, ensure the transaction fee is reasonable. | ||||
| 	tx := args.toTransaction() | ||||
| 	if err := checkTxFee(tx.GasPrice(), tx.Gas(), s.b.RPCTxFeeCap()); err != nil { | ||||
| 		return nil, err | ||||
| @@ -1008,8 +1008,19 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr | ||||
| 		} | ||||
| 		hi = block.GasLimit() | ||||
| 	} | ||||
| 	// Normalize the max fee per gas the call is willing to spend. | ||||
| 	var feeCap *big.Int | ||||
| 	if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) { | ||||
| 		return 0, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified") | ||||
| 	} else if args.GasPrice != nil { | ||||
| 		feeCap = args.GasPrice.ToInt() | ||||
| 	} else if args.MaxFeePerGas != nil { | ||||
| 		feeCap = args.MaxFeePerGas.ToInt() | ||||
| 	} else { | ||||
| 		feeCap = common.Big0 | ||||
| 	} | ||||
| 	// Recap the highest gas limit with account's available balance. | ||||
| 	if args.GasPrice != nil && args.GasPrice.ToInt().BitLen() != 0 { | ||||
| 	if feeCap.BitLen() != 0 { | ||||
| 		state, _, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) | ||||
| 		if err != nil { | ||||
| 			return 0, err | ||||
| @@ -1022,7 +1033,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr | ||||
| 			} | ||||
| 			available.Sub(available, args.Value.ToInt()) | ||||
| 		} | ||||
| 		allowance := new(big.Int).Div(available, args.GasPrice.ToInt()) | ||||
| 		allowance := new(big.Int).Div(available, feeCap) | ||||
|  | ||||
| 		// If the allowance is larger than maximum uint64, skip checking | ||||
| 		if allowance.IsUint64() && hi > allowance.Uint64() { | ||||
| @@ -1031,7 +1042,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr | ||||
| 				transfer = new(hexutil.Big) | ||||
| 			} | ||||
| 			log.Warn("Gas estimation capped by limited funds", "original", hi, "balance", balance, | ||||
| 				"sent", transfer.ToInt(), "gasprice", args.GasPrice.ToInt(), "fundable", allowance) | ||||
| 				"sent", transfer.ToInt(), "maxFeePerGas", feeCap, "fundable", allowance) | ||||
| 			hi = allowance.Uint64() | ||||
| 		} | ||||
| 	} | ||||
|   | ||||
		Reference in New Issue
	
	Block a user