Skip to content

Commit 06eee2c

Browse files
authored
Remove exchange rate calculation for non CELO denominated txs in state_transition (#2299)
Fix state_transition producing invalid gas used values for pre-H fork transactions. Specifically the fix is ensuring that non CIP-66 transactions do not call GetExchangeRate on the fee currency in the debitFee function, since calling GetExchangeRate can hit some memory locations which can result in lower gas costs for accesses for the rest of the transaction.
1 parent ca3465c commit 06eee2c

File tree

1 file changed

+26
-25
lines changed

1 file changed

+26
-25
lines changed

core/state_transition.go

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -217,12 +217,12 @@ func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation b
217217
func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool, vmRunner vm.EVMRunner, sysCtx *SysContractCallCtx) *StateTransition {
218218
var gasPriceMinimum *big.Int
219219
if evm.ChainConfig().IsEspresso(evm.Context.BlockNumber) {
220-
var feeCurrency *common.Address = msg.FeeCurrency()
221220
if msg.MaxFeeInFeeCurrency() != nil {
222221
// Celo denominated tx
223-
feeCurrency = nil
222+
gasPriceMinimum = sysCtx.GetGasPriceMinimum(nil)
223+
} else {
224+
gasPriceMinimum = sysCtx.GetGasPriceMinimum(msg.FeeCurrency())
224225
}
225-
gasPriceMinimum = sysCtx.GetGasPriceMinimum(feeCurrency)
226226
} else {
227227
gasPriceMinimum, _ = gpm.GetBaseFeeForCurrency(vmRunner, msg.FeeCurrency(), nil)
228228
}
@@ -264,7 +264,7 @@ func (st *StateTransition) to() common.Address {
264264
}
265265

266266
// payFees deducts gas and gateway fees from sender balance and adds the purchased amount of gas to the state.
267-
func (st *StateTransition) payFees(espresso bool, feeCurrencyRate *currency.ExchangeRate) error {
267+
func (st *StateTransition) payFees(espresso bool, denominatedCurrencyRate *currency.ExchangeRate) error {
268268
var isWhiteListed bool
269269
if espresso {
270270
isWhiteListed = st.sysCtx.IsWhitelisted(st.msg.FeeCurrency())
@@ -275,7 +275,7 @@ func (st *StateTransition) payFees(espresso bool, feeCurrencyRate *currency.Exch
275275
log.Trace("Fee currency not whitelisted", "fee currency address", st.msg.FeeCurrency())
276276
return ErrNonWhitelistedFeeCurrency
277277
}
278-
if err := st.canPayFee(st.msg.From(), st.msg.FeeCurrency(), espresso, feeCurrencyRate); err != nil {
278+
if err := st.canPayFee(st.msg.From(), st.msg.FeeCurrency(), espresso, denominatedCurrencyRate); err != nil {
279279
return err
280280
}
281281
if err := st.gp.SubGas(st.msg.Gas()); err != nil {
@@ -284,7 +284,7 @@ func (st *StateTransition) payFees(espresso bool, feeCurrencyRate *currency.Exch
284284

285285
st.initialGas = st.msg.Gas()
286286
st.gas += st.msg.Gas()
287-
err := st.debitFee(st.msg.From(), st.msg.FeeCurrency(), feeCurrencyRate)
287+
err := st.debitFee(st.msg.From(), st.msg.FeeCurrency(), denominatedCurrencyRate)
288288
return err
289289
}
290290

@@ -297,7 +297,7 @@ func (st *StateTransition) payFees(espresso bool, feeCurrencyRate *currency.Exch
297297
// For non-native tokens(cUSD, cEUR, ...) as feeCurrency:
298298
// - Pre-Espresso: it ensures balance > GasPrice * gas + gatewayFee (3)
299299
// - Post-Espresso: it ensures balance >= GasFeeCap * gas + gatewayFee (4)
300-
func (st *StateTransition) canPayFee(accountOwner common.Address, feeCurrency *common.Address, espresso bool, feeCurrencyRate *currency.ExchangeRate) error {
300+
func (st *StateTransition) canPayFee(accountOwner common.Address, feeCurrency *common.Address, espresso bool, denominatedCurrencyRate *currency.ExchangeRate) error {
301301
if feeCurrency == nil {
302302
balance := st.state.GetBalance(st.msg.From())
303303
if espresso {
@@ -340,7 +340,7 @@ func (st *StateTransition) canPayFee(accountOwner common.Address, feeCurrency *c
340340
if st.msg.MaxFeeInFeeCurrency() != nil {
341341
// Celo Denominated Tx: max fee is a tx field
342342
// Translate fees to feeCurrency
343-
feeGap = feeCurrencyRate.FromBase(feeGap)
343+
feeGap = denominatedCurrencyRate.FromBase(feeGap)
344344
// Check that fee <= MaxFeeInFeeCurrency
345345
if feeGap.Cmp(st.msg.MaxFeeInFeeCurrency()) > 0 {
346346
return ErrDenominatedLowMaxFee
@@ -363,7 +363,7 @@ func (st *StateTransition) canPayFee(accountOwner common.Address, feeCurrency *c
363363
return nil
364364
}
365365

366-
func (st *StateTransition) debitFee(from common.Address, feeCurrency *common.Address, feeCurrencyRate *currency.ExchangeRate) (err error) {
366+
func (st *StateTransition) debitFee(from common.Address, feeCurrency *common.Address, denominatedCurrencyRate *currency.ExchangeRate) (err error) {
367367
if st.evm.Config.SkipDebitCredit {
368368
return nil
369369
}
@@ -378,16 +378,12 @@ func (st *StateTransition) debitFee(from common.Address, feeCurrency *common.Add
378378
st.state.SubBalance(from, effectiveFee)
379379
return nil
380380
} else {
381-
var currencyFee *big.Int
382-
if st.msg.MaxFeeInFeeCurrency() == nil {
383-
// Normal feeCurrency tx
384-
currencyFee = effectiveFee
381+
if st.msg.MaxFeeInFeeCurrency() != nil {
382+
st.erc20FeeDebited = denominatedCurrencyRate.FromBase(effectiveFee)
385383
} else {
386-
// Celo denominated tx
387-
currencyFee = feeCurrencyRate.FromBase(effectiveFee)
384+
st.erc20FeeDebited = effectiveFee
388385
}
389-
st.erc20FeeDebited = currencyFee
390-
return erc20gas.DebitFees(st.evm, from, currencyFee, feeCurrency)
386+
return erc20gas.DebitFees(st.evm, from, st.erc20FeeDebited, feeCurrency)
391387
}
392388
}
393389

@@ -482,9 +478,14 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
482478
if st.msg.FeeCurrency() == nil && st.msg.MaxFeeInFeeCurrency() != nil {
483479
return nil, ErrDenominatedNoCurrency
484480
}
485-
feeCurrencyRate, err := currency.GetExchangeRate(st.vmRunner, st.msg.FeeCurrency())
486-
if err != nil {
487-
return nil, err
481+
var denominatedCurrencyRate *currency.ExchangeRate
482+
// Get rate only for CELO denominated txs (H fork)
483+
if st.msg.MaxFeeInFeeCurrency() != nil {
484+
var err error
485+
denominatedCurrencyRate, err = currency.GetExchangeRate(st.vmRunner, st.msg.FeeCurrency())
486+
if err != nil {
487+
return nil, err
488+
}
488489
}
489490

490491
// Check clauses 1-2
@@ -517,7 +518,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
517518
return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.msg.Gas(), gas)
518519
}
519520
// Check clauses 3-4, pay the fees (which buys gas), and subtract the intrinsic gas
520-
err = st.payFees(espresso, feeCurrencyRate)
521+
err = st.payFees(espresso, denominatedCurrencyRate)
521522
if err != nil {
522523
log.Error("Transaction failed to buy gas", "err", err, "gas", gas)
523524
return nil, err
@@ -553,7 +554,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
553554
st.refundGas(params.RefundQuotientEIP3529)
554555
}
555556

556-
err = st.creditTxFees(feeCurrencyRate)
557+
err = st.creditTxFees(denominatedCurrencyRate)
557558
if err != nil {
558559
return nil, err
559560
}
@@ -565,7 +566,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
565566
}
566567

567568
// creditTxFees calculates the amounts and recipients of transaction fees and credits the accounts.
568-
func (st *StateTransition) creditTxFees(feeCurrencyRate *currency.ExchangeRate) error {
569+
func (st *StateTransition) creditTxFees(denominatedCurrencyRate *currency.ExchangeRate) error {
569570
if st.evm.Config.SkipDebitCredit {
570571
return nil
571572
}
@@ -596,8 +597,8 @@ func (st *StateTransition) creditTxFees(feeCurrencyRate *currency.ExchangeRate)
596597
// conversions have limited accuracy, the only way to achieve this
597598
// is to calculate one of the three credit values based on the two
598599
// others after the exchange rate conversion.
599-
tipTxFee = feeCurrencyRate.FromBase(tipTxFee)
600-
baseTxFee = feeCurrencyRate.FromBase(baseTxFee)
600+
tipTxFee = denominatedCurrencyRate.FromBase(tipTxFee)
601+
baseTxFee = denominatedCurrencyRate.FromBase(baseTxFee)
601602
totalTxFee.Add(tipTxFee, baseTxFee)
602603
refund.Sub(st.erc20FeeDebited, totalTxFee) // refund = debited - tip - basefee
603604
// No need to exchange gateway fee since it's it's deprecated on G fork,

0 commit comments

Comments
 (0)