Skip to content

Commit dfab1de

Browse files
Merge pull request #348 from OffchainLabs/gligneul/nit-5020
Backport(consensus): Do not combine multi-gas refunds with EVM refunds
2 parents d162cc1 + c9fbd05 commit dfab1de

3 files changed

Lines changed: 20 additions & 35 deletions

File tree

arbos/l2pricing/model.go

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"math/big"
99

1010
"github.com/ethereum/go-ethereum/arbitrum/multigas"
11-
"github.com/ethereum/go-ethereum/log"
1211
"github.com/ethereum/go-ethereum/params"
1312

1413
"github.com/offchainlabs/nitro/arbos/storage"
@@ -366,6 +365,9 @@ func (ps *L2PricingState) GetMultiGasBaseFeePerResource(blockBaseFee *big.Int) (
366365
return fees, nil
367366
}
368367

368+
// MultiDimensionalPriceForRefund returns the multi-gas fee considering each dimension's base-fee.
369+
// It doesn't take in consideration EVM SSTORE refunds. So, the transaction will be charged the
370+
// minimum between `single-gas fee minus EVM refunds` AND `multi-gas fee without EVM refunds`.
369371
func (ps *L2PricingState) MultiDimensionalPriceForRefund(usedMultiGas multigas.MultiGas, blockBaseFee *big.Int) (*big.Int, error) {
370372
fees, err := ps.GetMultiGasBaseFeePerResource(blockBaseFee)
371373
if err != nil {
@@ -388,19 +390,6 @@ func (ps *L2PricingState) MultiDimensionalPriceForRefund(usedMultiGas multigas.M
388390
)
389391
total.Add(total, part)
390392
}
391-
392-
// Take in consideration evm refunds using the block base fee.
393-
if ps.ArbosVersion >= params.ArbosVersion_MultiGasRefundFix {
394-
evmRefunds := new(big.Int).Mul(new(big.Int).SetUint64(usedMultiGas.GetRefund()), blockBaseFee)
395-
if total.Cmp(evmRefunds) > 0 {
396-
// This should always be true, but check anyway to ensure we don't return a negative value.
397-
total.Sub(total, evmRefunds)
398-
} else {
399-
log.Warn("EVM refund greater than multi-gas fee",
400-
"multi-gas-fee", total, "evm-refunds", evmRefunds)
401-
}
402-
}
403-
404393
return total, nil
405394
}
406395

arbos/tx_processor_multigas_test.go

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -273,12 +273,9 @@ func TestEndTxHookMultiGasRefundRetryableTx(t *testing.T) {
273273
)
274274
}
275275

276-
// TestEndTxHookMultiGasRefundWithEVMRefundCredit verifies that the multi-gas
277-
// refund stays invariant under EVM SSTORE refunds (EIP-3529). usedMultiGas's
278-
// per-kind sum is pre-refund (peak); on v61+ MultiDimensionalPriceForRefund
279-
// subtracts usedMultiGas.GetRefund() * baseFee from its result so it can be
280-
// paired with the net totalCost = baseFee * (gasLimit - gasLeft) computed in
281-
// EndTxHook.
276+
// TestEndTxHookMultiGasRefundWithEVMRefundCredit verifies that the EndTxHook doesn't give extra refunds when the EVM
277+
// refunds are greater than the multi-dimensional one.
278+
// The EVM refunds are given back to the user before EndTxHook is called, in stateTransition.returnGas().
282279
func TestEndTxHookMultiGasRefundWithEVMRefundCredit(t *testing.T) {
283280
const gasLimit uint64 = 1_000_000
284281
const evmRefundCredit uint64 = 200_000 // EIP-3529 cap
@@ -302,40 +299,37 @@ func TestEndTxHookMultiGasRefundWithEVMRefundCredit(t *testing.T) {
302299
pricing := txProcessor.state.L2PricingState()
303300
pricing.ArbosVersion = params.ArbosVersion_MultiGasRefundFix
304301

302+
// Set a 99/100 ratio to make the multi-gas refund smaller than the EVM refunds.
305303
Require(t, pricing.AddMultiGasConstraint(
306304
100_000,
307305
10,
308306
200_000_000_000,
309307
map[uint8]uint64{
310-
uint8(multigas.ResourceKindComputation): 1,
311-
uint8(multigas.ResourceKindStorageGrowth): 10,
308+
uint8(multigas.ResourceKindComputation): 99,
309+
uint8(multigas.ResourceKindStorageGrowth): 100,
312310
},
313311
))
314-
pricing.UpdatePricingModel(100)
312+
pricing.UpdatePricingModel(1)
315313
require.NoError(t, pricing.CommitMultiGasFees())
316314

317315
baseFee, err := pricing.BaseFeeWei()
318316
require.NoError(t, err)
319-
evm.Context.BaseFee = new(big.Int).Set(baseFee)
317+
evm.Context.BaseFee = baseFee
320318

321319
gasUsed := gasLimit - gasLeft
322320
peakGasUsed := gasUsed + evmRefundCredit
323321
usedMultiGas := multigas.MultiGasFromPairs(
324322
multigas.Pair{Kind: multigas.ResourceKindComputation, Amount: peakGasUsed / 2},
325-
multigas.Pair{Kind: multigas.ResourceKindStorageAccessRead, Amount: peakGasUsed / 2},
323+
multigas.Pair{Kind: multigas.ResourceKindStorageGrowth, Amount: peakGasUsed / 2},
326324
).WithRefund(evmRefundCredit)
327325

328-
multiDimensionalCost, err := pricing.MultiDimensionalPriceForRefund(usedMultiGas, baseFee)
326+
multiGasFee, err := pricing.MultiDimensionalPriceForRefund(usedMultiGas, baseFee)
329327
require.NoError(t, err)
330-
totalCost := new(big.Int).Mul(baseFee, new(big.Int).SetUint64(gasUsed))
331-
expectedRefund := new(big.Int).Sub(totalCost, multiDimensionalCost)
332-
require.True(t, expectedRefund.Sign() > 0, "expected positive multi-gas refund, got %v", expectedRefund)
328+
singleGasFee := new(big.Int).Mul(baseFee, new(big.Int).SetUint64(gasUsed))
329+
require.Negative(t, singleGasFee.Cmp(multiGasFee), "expected singleGasFee < multiGasFee")
333330

331+
// Expect zero balance because the EVM refunds are given before EndTxHook is called.
334332
txProcessor.EndTxHook(gasLeft, usedMultiGas, true)
335-
336-
require.True(t,
337-
arbmath.BigEquals(expectedRefund, evm.StateDB.GetBalance(from).ToBig()),
338-
"refund mismatch under EVM refund credit: got %v, want %v",
339-
evm.StateDB.GetBalance(from).ToBig(), expectedRefund,
340-
)
333+
balance := evm.StateDB.GetBalance(from).ToBig()
334+
require.Zero(t, balance.Sign(), "unexpected refund in EndTxHook")
341335
}

changelog/gligneul-nit-5019.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
### Fixed
2+
- Do not combine multi-gas refunds with EVM refunds.

0 commit comments

Comments
 (0)