Skip to content

Commit

Permalink
fix: gas consumption in ApplyEvmMsg
Browse files Browse the repository at this point in the history
  • Loading branch information
k-yang committed Jan 27, 2025
1 parent 1cb2068 commit 9947330
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 47 deletions.
6 changes: 4 additions & 2 deletions x/evm/keeper/call_contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func (k Keeper) CallContractWithInput(
) (evmResp *evm.MsgEthereumTxResponse, err error) {
// This is a `defer` pattern to add behavior that runs in the case that the
// error is non-nil, creating a concise way to add extra information.
defer HandleOutOfGasPanic(&err, "CallContractError")
defer HandleOutOfGasPanic(&err, "CallContractError")()
nonce := k.GetAccNonce(ctx, fromAcc)

unusedBigInt := big.NewInt(0)
Expand All @@ -63,7 +63,9 @@ func (k Keeper) CallContractWithInput(
evmResp, err = k.ApplyEvmMsg(
ctx, evmMsg, evmObj, evm.NewNoOpTracer(), commit, txConfig.TxHash, true,
)
ctx.GasMeter().ConsumeGas(evmResp.GasUsed, "CallContractWithInput")
if evmResp != nil {
ctx.GasMeter().ConsumeGas(evmResp.GasUsed, "CallContractWithInput")
}
if err != nil {
return nil, errors.Wrap(err, "failed to apply ethereum core message")
}
Expand Down
3 changes: 1 addition & 2 deletions x/evm/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,13 +128,12 @@ func HandleOutOfGasPanic(err *error, format string) func() {
if r := recover(); r != nil {
switch r.(type) {
case sdk.ErrorOutOfGas:

*err = vm.ErrOutOfGas
default:
panic(r)
}
}
if err != nil && format != "" {
if *err != nil && format != "" {
*err = fmt.Errorf("%s: %w", format, *err)
}
}
Expand Down
72 changes: 31 additions & 41 deletions x/evm/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"strconv"

"cosmossdk.io/errors"
"cosmossdk.io/math"
tmbytes "github.com/cometbft/cometbft/libs/bytes"
tmtypes "github.com/cometbft/cometbft/types"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand Down Expand Up @@ -73,7 +72,9 @@ func (k *Keeper) EthereumTx(
txConfig.TxHash,
false, /*fullRefundLeftoverGas*/
)
ctx.GasMeter().ConsumeGas(evmResp.GasUsed, "execute ethereum tx")
if evmResp != nil {
ctx.GasMeter().ConsumeGas(evmResp.GasUsed, "execute ethereum tx")
}
if err != nil {
return nil, errors.Wrap(err, "error applying ethereum core message")
}
Expand Down Expand Up @@ -261,21 +262,20 @@ func (k *Keeper) ApplyEvmMsg(
txHash gethcommon.Hash,
fullRefundLeftoverGas bool,
) (resp *evm.MsgEthereumTxResponse, err error) {
leftoverGas := msg.Gas()
gasRemaining := msg.Gas()

// Allow the tracer captures the tx level events, mainly the gas consumption.
vmCfg := evmObj.Config
if vmCfg.Debug {
vmCfg.Tracer.CaptureTxStart(leftoverGas)
vmCfg.Tracer.CaptureTxStart(gasRemaining)
defer func() {
vmCfg.Tracer.CaptureTxEnd(leftoverGas)
vmCfg.Tracer.CaptureTxEnd(gasRemaining)
}()
}

sender := vm.AccountRef(msg.From())
contractCreation := msg.To() == nil

intrinsicGas, err := core.IntrinsicGas(
intrinsicGasCost, err := core.IntrinsicGas(
msg.Data(), msg.AccessList(),
contractCreation, true, true,
)
Expand All @@ -290,15 +290,15 @@ func (k *Keeper) ApplyEvmMsg(
//
// Should check again even if it is checked on Ante Handler, because eth_call
// don't go through Ante Handler.
if leftoverGas < intrinsicGas {
if gasRemaining < intrinsicGasCost {
// eth_estimateGas will check for this exact error
return nil, errors.Wrapf(
core.ErrIntrinsicGas,
"ApplyEvmMsg: provided msg.Gas (%d) is less than intrinsic gas cost (%d)",
leftoverGas, intrinsicGas,
gasRemaining, intrinsicGasCost,
)
}
leftoverGas = leftoverGas - intrinsicGas
gasRemaining -= intrinsicGasCost

// access list preparation is moved from ante handler to here, because it's
// needed when `ApplyMessage` is called under contexts where ante handlers
Expand All @@ -318,28 +318,28 @@ func (k *Keeper) ApplyEvmMsg(
// take over the nonce management from evm:
// - reset sender's nonce to msg.Nonce() before calling evm.
// - increase sender's nonce by one no matter the result.
evmObj.StateDB.SetNonce(sender.Address(), msg.Nonce())
evmObj.StateDB.SetNonce(msg.From(), msg.Nonce())

var ret []byte
var returnBz []byte
var vmErr error
if contractCreation {
ret, _, leftoverGas, vmErr = evmObj.Create(
sender,
returnBz, _, gasRemaining, vmErr = evmObj.Create(
vm.AccountRef(msg.From()),
msg.Data(),
leftoverGas,
gasRemaining,
msgWei,
)
} else {
ret, leftoverGas, vmErr = evmObj.Call(
sender,
returnBz, gasRemaining, vmErr = evmObj.Call(
vm.AccountRef(msg.From()),
*msg.To(),
msg.Data(),
leftoverGas,
gasRemaining,
msgWei,
)
}
// Increment nonce after processing the message
evmObj.StateDB.SetNonce(sender.Address(), msg.Nonce()+1)
evmObj.StateDB.SetNonce(msg.From(), msg.Nonce()+1)

// EVM execution error needs to be available for the JSON-RPC client
var vmError string
Expand All @@ -353,10 +353,6 @@ func (k *Keeper) ApplyEvmMsg(
return nil, errors.Wrap(err, "ApplyEvmMsg: failed to commit stateDB")
}
}
// Rare case of uint64 gas overflow
if msg.Gas() < leftoverGas {
return nil, errors.Wrapf(core.ErrGasUintOverflow, "ApplyEvmMsg: message gas limit (%d) < leftover gas (%d)", msg.Gas(), leftoverGas)
}

// TODO: UD-DEBUG: Clarify text below.
// GAS REFUND
Expand All @@ -373,31 +369,25 @@ func (k *Keeper) ApplyEvmMsg(
if fullRefundLeftoverGas {
refundQuotient = 1 // 100% refund
}
temporaryGasUsed := msg.Gas() - leftoverGas
refund := GasToRefund(evmObj.StateDB.GetRefund(), temporaryGasUsed, refundQuotient)

// update leftoverGas and temporaryGasUsed with refund amount
leftoverGas += refund
temporaryGasUsed -= refund
if msg.Gas() < leftoverGas {
return nil, errors.Wrapf(core.ErrGasUintOverflow, "ApplyEvmMsg: message gas limit (%d) < leftover gas (%d)", msg.Gas(), leftoverGas)
}

// Min gas used is a % of gasLimit
gasUsed := math.LegacyNewDec(int64(temporaryGasUsed)).TruncateInt().Uint64()
gasUsed := msg.Gas() - gasRemaining
refund := GasToRefund(evmObj.StateDB.GetRefund(), gasUsed, refundQuotient)

// This resulting "leftoverGas" is used by the tracer. This happens as a
// result of the defer statement near the beginning of the function with
// "vm.Tracer".
leftoverGas = msg.Gas() - gasUsed
gasRemaining += refund
gasUsed -= refund

return &evm.MsgEthereumTxResponse{
evmResp := &evm.MsgEthereumTxResponse{
GasUsed: gasUsed,
VmError: vmError,
Ret: ret,
Ret: returnBz,
Logs: evm.NewLogsFromEth(evmObj.StateDB.(*statedb.StateDB).Logs()),
Hash: txHash.Hex(),
}, nil
}

if gasRemaining > msg.Gas() {
return evmResp, errors.Wrapf(core.ErrGasUintOverflow, "ApplyEvmMsg: message gas limit (%d) < leftover gas (%d)", msg.Gas(), gasRemaining)
}
return evmResp, nil
}

func ParseWeiAsMultipleOfMicronibi(weiInt *big.Int) (newWeiInt *big.Int, err error) {
Expand Down
3 changes: 1 addition & 2 deletions x/evm/precompile/funtoken.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,7 @@ func (p precompileFunToken) sendToBank(

erc20, amount, to, err := p.parseArgsSendToBank(args)
if err != nil {
err = ErrInvalidArgs(err)
return
return nil, ErrInvalidArgs(err)
}

var evmResponses []*evm.MsgEthereumTxResponse
Expand Down

0 comments on commit 9947330

Please sign in to comment.