From ea9cfcdf6e9aa50a1564851cbc083c857be6b352 Mon Sep 17 00:00:00 2001 From: Somnath Date: Wed, 4 Sep 2024 16:58:30 +0400 Subject: [PATCH] core: Check `gasBailout` before deducting balance in trace_call (#11813) **Existing behaviour:** - Add up the possible value that user must pay beforehand to buy gas - Deduct that amount from the sender's account in `intraBlockState`, but: - Don't deduct the gas value amount if the user doesn't have enough, and `gasBailout` is set **New behaviour:** - Don't check if sender's balance is enough to pay gas value amount, nor deduct it, if `gasBailout` is set **More rationale** This would mean the sender's account would show `"balance": "="` in `trace_call` rpc method, that is, no change, if gas is the only thing the user pays for. This is fine because the gas price can fluctuate in a real transaction. This also removes the inconsistency of sometimes having to bother deducting the amount if it is less than sender's balance, thereby causing a bug/inconsistency. --- core/state_transition.go | 51 +++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 29 deletions(-) diff --git a/core/state_transition.go b/core/state_transition.go index 9b61dda9e84..fe7621042ee 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -192,49 +192,42 @@ func (st *StateTransition) buyGas(gasBailout bool) error { } } - balanceCheck := gasVal - if st.gasFeeCap != nil { - balanceCheck = st.sharedBuyGasBalance.SetUint64(st.msg.Gas()) - balanceCheck, overflow = balanceCheck.MulOverflow(balanceCheck, st.gasFeeCap) - if overflow { - return fmt.Errorf("%w: address %v", ErrInsufficientFunds, st.msg.From().Hex()) - } - balanceCheck, overflow = balanceCheck.AddOverflow(balanceCheck, st.value) - if overflow { - return fmt.Errorf("%w: address %v", ErrInsufficientFunds, st.msg.From().Hex()) - } - if st.evm.ChainRules().IsCancun { - maxBlobFee, overflow := new(uint256.Int).MulOverflow(st.msg.MaxFeePerBlobGas(), new(uint256.Int).SetUint64(st.msg.BlobGas())) + if !gasBailout { + balanceCheck := gasVal + if st.gasFeeCap != nil { + balanceCheck = st.sharedBuyGasBalance.SetUint64(st.msg.Gas()) + balanceCheck, overflow = balanceCheck.MulOverflow(balanceCheck, st.gasFeeCap) if overflow { return fmt.Errorf("%w: address %v", ErrInsufficientFunds, st.msg.From().Hex()) } - balanceCheck, overflow = balanceCheck.AddOverflow(balanceCheck, maxBlobFee) + balanceCheck, overflow = balanceCheck.AddOverflow(balanceCheck, st.value) if overflow { return fmt.Errorf("%w: address %v", ErrInsufficientFunds, st.msg.From().Hex()) } + if st.evm.ChainRules().IsCancun { + maxBlobFee, overflow := new(uint256.Int).MulOverflow(st.msg.MaxFeePerBlobGas(), new(uint256.Int).SetUint64(st.msg.BlobGas())) + if overflow { + return fmt.Errorf("%w: address %v", ErrInsufficientFunds, st.msg.From().Hex()) + } + balanceCheck, overflow = balanceCheck.AddOverflow(balanceCheck, maxBlobFee) + if overflow { + return fmt.Errorf("%w: address %v", ErrInsufficientFunds, st.msg.From().Hex()) + } + } } - } - var subBalance = false - if have, want := st.state.GetBalance(st.msg.From()), balanceCheck; have.Cmp(want) < 0 { - if !gasBailout { + if have, want := st.state.GetBalance(st.msg.From()), balanceCheck; have.Cmp(want) < 0 { return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From().Hex(), have, want) } - } else { - subBalance = true + st.state.SubBalance(st.msg.From(), gasVal, tracing.BalanceDecreaseGasBuy) + st.state.SubBalance(st.msg.From(), blobGasVal, tracing.BalanceDecreaseGasBuy) } + if err := st.gp.SubGas(st.msg.Gas()); err != nil { - if !gasBailout { - return err - } + return err } st.gasRemaining += st.msg.Gas() st.initialGas = st.msg.Gas() st.evm.BlobFee = blobGasVal - - if subBalance { - st.state.SubBalance(st.msg.From(), gasVal, tracing.BalanceDecreaseGasBuy) - st.state.SubBalance(st.msg.From(), blobGasVal, tracing.BalanceDecreaseGasBuy) - } return nil } @@ -456,7 +449,7 @@ func (st *StateTransition) TransitionDb(refunds bool, gasBailout bool) (*evmtype } else { ret, st.gasRemaining, vmerr = st.evm.Call(sender, st.to(), st.data, st.gasRemaining, st.value, bailout) } - if refunds { + if refunds && !gasBailout { if rules.IsLondon { // After EIP-3529: refunds are capped to gasUsed / 5 st.refundGas(params.RefundQuotientEIP3529)