From b081cd5da501f538cda419416e2cf47e94cc98d8 Mon Sep 17 00:00:00 2001 From: "lightclient@protonmail.com" Date: Sat, 31 Jul 2021 23:09:46 +0200 Subject: [PATCH 1/5] internal/ethapi/api: cap highest gas limit by account balance for 1559 fee parameters --- internal/ethapi/api.go | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 826934a9c1bd..a35e7e7d1a3d 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1008,8 +1008,21 @@ 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 maxFeePerGas *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 { + maxFeePerGas = args.GasPrice.ToInt() + } else if args.MaxFeePerGas != nil { + maxFeePerGas = args.MaxFeePerGas.ToInt() + } else { + maxFeePerGas = common.Big0 + } + // Recap the highest gas limit with account's available balance. - if args.GasPrice != nil && args.GasPrice.ToInt().BitLen() != 0 { + if maxFeePerGas.BitLen() != 0 { state, _, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) if err != nil { return 0, err @@ -1022,7 +1035,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, maxFeePerGas) // If the allowance is larger than maximum uint64, skip checking if allowance.IsUint64() && hi > allowance.Uint64() { @@ -1031,7 +1044,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", maxFeePerGas, "fundable", allowance) hi = allowance.Uint64() } } From 6d8d170d293b702904ecee747a0a5260f3b36a50 Mon Sep 17 00:00:00 2001 From: "lightclient@protonmail.com" Date: Mon, 2 Aug 2021 15:40:40 +0200 Subject: [PATCH 2/5] accounts/abi/bind: port gas limit cap for 1559 parameters to simulated backend --- accounts/abi/bind/backends/simulated.go | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 06cd0908e746..2f6f3d1dba86 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -488,8 +488,21 @@ 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 (gasFeeCap or gasTipCap) 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 +511,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() } } From 2309bf7c9e2a71c96af3e1972a36d4d648aac128 Mon Sep 17 00:00:00 2001 From: "lightclient@protonmail.com" Date: Mon, 2 Aug 2021 16:54:47 +0200 Subject: [PATCH 3/5] accounts/abi/bind: add test for 1559 gas estimates for the simulated backend --- accounts/abi/bind/backends/simulated_test.go | 23 ++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/accounts/abi/bind/backends/simulated_test.go b/accounts/abi/bind/backends/simulated_test.go index 0257e3e8702c..613267810744 100644 --- a/accounts/abi/bind/backends/simulated_test.go +++ b/accounts/abi/bind/backends/simulated_test.go @@ -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) } From 5dad10a36b9bfb8f852d85e1caf0968c502111b1 Mon Sep 17 00:00:00 2001 From: "lightclient@protonmail.com" Date: Wed, 4 Aug 2021 22:48:27 +0200 Subject: [PATCH 4/5] internal/ethapi/api: fix comment --- internal/ethapi/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index a35e7e7d1a3d..6ca8426321b0 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -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 From b9e17137208c8a78b46172980a1858ee5fa3284b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 10 Aug 2021 16:45:05 +0300 Subject: [PATCH 5/5] accounts/abi/bind/backends, internal/ethapi: unify naming style --- accounts/abi/bind/backends/simulated.go | 4 +--- internal/ethapi/api.go | 16 +++++++--------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 2f6f3d1dba86..cb4eea3a0dc0 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -488,11 +488,10 @@ 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 (gasFeeCap or gasTipCap) specified") + return 0, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified") } else if call.GasPrice != nil { feeCap = call.GasPrice } else if call.GasFeeCap != nil { @@ -500,7 +499,6 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMs } else { feeCap = common.Big0 } - // Recap the highest gas allowance with account's balance. if feeCap.BitLen() != 0 { balance := b.pendingState.GetBalance(call.From) // from can't be nil diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 6ca8426321b0..795069b649c7 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1008,21 +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 maxFeePerGas *big.Int + 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 { - maxFeePerGas = args.GasPrice.ToInt() + feeCap = args.GasPrice.ToInt() } else if args.MaxFeePerGas != nil { - maxFeePerGas = args.MaxFeePerGas.ToInt() + feeCap = args.MaxFeePerGas.ToInt() } else { - maxFeePerGas = common.Big0 + feeCap = common.Big0 } - // Recap the highest gas limit with account's available balance. - if maxFeePerGas.BitLen() != 0 { + if feeCap.BitLen() != 0 { state, _, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) if err != nil { return 0, err @@ -1035,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, maxFeePerGas) + allowance := new(big.Int).Div(available, feeCap) // If the allowance is larger than maximum uint64, skip checking if allowance.IsUint64() && hi > allowance.Uint64() { @@ -1044,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(), "maxFeePerGas", maxFeePerGas, "fundable", allowance) + "sent", transfer.ToInt(), "maxFeePerGas", feeCap, "fundable", allowance) hi = allowance.Uint64() } }