ante, evm: update gas consumption logic (#178)

* clean up logic by ignoring cosmos gas meter

* set gas used in txResponse

* reset and set the gas in context

* rename ante handler

* fix refundedgas logic

* remove gas update logic in keeper

* update context in keeper

* add test for EthSetupContextDecorator

* fix broken test due to gas logic change
This commit is contained in:
Thomas Nguy 2021-06-30 18:31:30 +09:00 committed by GitHub
parent 036ffb7a39
commit 5ba8ffe669
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 170 additions and 166 deletions

View File

@ -60,7 +60,7 @@ func NewAnteHandler(
// handle as *evmtypes.MsgEthereumTx
anteHandler = sdk.ChainAnteDecorators(
authante.NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first
NewEthSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first
authante.NewMempoolFeeDecorator(),
authante.NewTxTimeoutHeightDecorator(),
authante.NewValidateMemoDecorator(ak),

View File

@ -56,13 +56,9 @@ func (esvd EthSigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, s
)
}
// get and set account must be called with an infinite gas meter in order to prevent
// additional gas from being deducted.
infCtx := ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
chainID := esvd.evmKeeper.ChainID()
config, found := esvd.evmKeeper.GetChainConfig(infCtx)
config, found := esvd.evmKeeper.GetChainConfig(ctx)
if !found {
return ctx, evmtypes.ErrChainConfigNotFound
}
@ -122,11 +118,8 @@ func (avd EthAccountVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx
return next(ctx, tx, simulate)
}
// get and set account must be called with an infinite gas meter in order to prevent
// additional gas from being deducted.
infCtx := ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
avd.evmKeeper.WithContext(infCtx)
evmDenom := avd.evmKeeper.GetParams(infCtx).EvmDenom
avd.evmKeeper.WithContext(ctx)
evmDenom := avd.evmKeeper.GetParams(ctx).EvmDenom
for i, msg := range tx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
@ -154,14 +147,14 @@ func (avd EthAccountVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx
"the sender is not EOA: address <%v>, codeHash <%s>", fromAddr, codeHash), "")
}
acc := avd.ak.GetAccount(infCtx, from)
acc := avd.ak.GetAccount(ctx, from)
if acc == nil {
acc = avd.ak.NewAccountWithAddress(infCtx, from)
avd.ak.SetAccount(infCtx, acc)
acc = avd.ak.NewAccountWithAddress(ctx, from)
avd.ak.SetAccount(ctx, acc)
}
// validate sender has enough funds to pay for tx cost
balance := avd.bankKeeper.GetBalance(infCtx, from, evmDenom)
balance := avd.bankKeeper.GetBalance(ctx, from, evmDenom)
if balance.Amount.BigInt().Cmp(msgEthTx.Cost()) < 0 {
return ctx, stacktrace.Propagate(
sdkerrors.Wrapf(
@ -199,10 +192,6 @@ func (nvd EthNonceVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx,
return next(ctx, tx, simulate)
}
// get and set account must be called with an infinite gas meter in order to prevent
// additional gas from being deducted.
infCtx := ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
for i, msg := range tx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
@ -213,7 +202,7 @@ func (nvd EthNonceVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx,
}
// sender address should be in the tx cache from the previous AnteHandle call
seq, err := nvd.ak.GetSequence(infCtx, msgEthTx.GetFrom())
seq, err := nvd.ak.GetSequence(ctx, msgEthTx.GetFrom())
if err != nil {
return ctx, stacktrace.Propagate(err, "sequence not found for address %s", msgEthTx.From)
}
@ -267,14 +256,10 @@ func NewEthGasConsumeDecorator(ak AccountKeeper, bankKeeper BankKeeper, ek EVMKe
// - user doesn't have enough balance to deduct the transaction fees (gas_limit * gas_price)
// - transaction or block gas meter runs out of gas
func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
// get and set account must be called with an infinite gas meter in order to prevent
// additional gas from being deducted.
infCtx := ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
// reset the refund gas value in the keeper for the current transaction
egcd.evmKeeper.ResetRefundTransient(infCtx)
egcd.evmKeeper.ResetRefundTransient(ctx)
config, found := egcd.evmKeeper.GetChainConfig(infCtx)
config, found := egcd.evmKeeper.GetChainConfig(ctx)
if !found {
return ctx, evmtypes.ErrChainConfigNotFound
}
@ -297,7 +282,7 @@ func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula
isContractCreation := msgEthTx.To() == nil
// fetch sender account from signature
signerAcc, err := authante.GetSignerAcc(infCtx, egcd.ak, msgEthTx.GetFrom())
signerAcc, err := authante.GetSignerAcc(ctx, egcd.ak, msgEthTx.GetFrom())
if err != nil {
return ctx, stacktrace.Propagate(err, "account not found for sender %s", msgEthTx.From)
}
@ -324,20 +309,16 @@ func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula
// calculate the fees paid to validators based on gas limit and price
feeAmt := msgEthTx.Fee() // fee = gas limit * gas price
evmDenom := egcd.evmKeeper.GetParams(infCtx).EvmDenom
evmDenom := egcd.evmKeeper.GetParams(ctx).EvmDenom
fees := sdk.Coins{sdk.NewCoin(evmDenom, sdk.NewIntFromBigInt(feeAmt))}
// deduct the full gas cost from the user balance
if err := authante.DeductFees(egcd.bankKeeper, infCtx, signerAcc, fees); err != nil {
if err := authante.DeductFees(egcd.bankKeeper, ctx, signerAcc, fees); err != nil {
return ctx, stacktrace.Propagate(
err,
"failed to deduct full gas cost %s from the user %s balance", fees, msgEthTx.From,
)
}
// consume intrinsic gas for the current transaction. After runTx is executed on Baseapp, the
// application will consume gas from the block gas pool.
ctx.GasMeter().ConsumeGas(intrinsicGas, "intrinsic gas")
}
// TODO: deprecate after https://github.com/cosmos/cosmos-sdk/issues/9514 is fixed on SDK
@ -373,12 +354,9 @@ func NewCanTransferDecorator(evmKeeper EVMKeeper) CanTransferDecorator {
// AnteHandle creates an EVM from the message and calls the BlockContext CanTransfer function to
// see if the address can execute the transaction.
func (ctd CanTransferDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
// get and set account must be called with an infinite gas meter in order to prevent
// additional gas from being deducted.
infCtx := ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
ctd.evmKeeper.WithContext(infCtx)
ctd.evmKeeper.WithContext(ctx)
config, found := ctd.evmKeeper.GetChainConfig(infCtx)
config, found := ctd.evmKeeper.GetChainConfig(ctx)
if !found {
return ctx, evmtypes.ErrChainConfigNotFound
}
@ -444,12 +422,8 @@ func NewAccessListDecorator(evmKeeper EVMKeeper) AccessListDecorator {
//
// The AnteHandler will only prepare the access list if Yolov3/Berlin/EIPs 2929 and 2930 are applicable at the current number.
func (ald AccessListDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
// get and set account must be called with an infinite gas meter in order to prevent
// additional gas from being deducted.
infCtx := ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
config, found := ald.evmKeeper.GetChainConfig(infCtx)
config, found := ald.evmKeeper.GetChainConfig(ctx)
if !found {
return ctx, evmtypes.ErrChainConfigNotFound
}
@ -464,7 +438,7 @@ func (ald AccessListDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate b
}
// setup the keeper context before setting the access list
ald.evmKeeper.WithContext(infCtx)
ald.evmKeeper.WithContext(ctx)
for i, msg := range tx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
@ -501,9 +475,6 @@ func NewEthIncrementSenderSequenceDecorator(ak AccountKeeper) EthIncrementSender
// contract creation, the nonce will be incremented during the transaction execution and not within
// this AnteHandler decorator.
func (issd EthIncrementSenderSequenceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
// get and set account must be called with an infinite gas meter in order to prevent
// additional gas from being deducted.
infCtx := ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
for i, msg := range tx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
@ -524,7 +495,7 @@ func (issd EthIncrementSenderSequenceDecorator) AnteHandle(ctx sdk.Context, tx s
// increment sequence of all signers
for _, addr := range msg.GetSigners() {
acc := issd.ak.GetAccount(infCtx, addr)
acc := issd.ak.GetAccount(ctx, addr)
if acc == nil {
return ctx, stacktrace.Propagate(
@ -540,7 +511,7 @@ func (issd EthIncrementSenderSequenceDecorator) AnteHandle(ctx sdk.Context, tx s
return ctx, stacktrace.Propagate(err, "failed to set sequence to %d", acc.GetSequence()+1)
}
issd.ak.SetAccount(infCtx, acc)
issd.ak.SetAccount(ctx, acc)
}
}
@ -571,3 +542,22 @@ func (vbd EthValidateBasicDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simu
return next(ctx, tx, simulate)
}
// EthSetupContextDecorator is adapted from SetUpContextDecorator from cosmos-sdk, it ignores gas consumption
// by setting the gas meter to infinite
type EthSetupContextDecorator struct{}
func NewEthSetUpContextDecorator() EthSetupContextDecorator {
return EthSetupContextDecorator{}
}
func (esc EthSetupContextDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
// all transactions must implement GasTx
_, ok := tx.(authante.GasTx)
if !ok {
return newCtx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be GasTx")
}
newCtx = ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
return next(newCtx, tx, simulate)
}

View File

@ -11,7 +11,6 @@ import (
"github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
)
func nextFn(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) {
@ -46,9 +45,7 @@ func (suite AnteTestSuite) TestEthSigVerificationDecorator() {
for _, tc := range testCases {
suite.Run(tc.name, func() {
consumed := suite.ctx.GasMeter().GasConsumed()
ctx, err := dec.AnteHandle(suite.ctx.WithIsReCheckTx(tc.reCheckTx), tc.tx, false, nextFn)
suite.Require().Equal(consumed, ctx.GasMeter().GasConsumed())
_, err := dec.AnteHandle(suite.ctx.WithIsReCheckTx(tc.reCheckTx), tc.tx, false, nextFn)
if tc.expPass {
suite.Require().NoError(err)
@ -133,10 +130,7 @@ func (suite AnteTestSuite) TestNewEthAccountVerificationDecorator() {
for _, tc := range testCases {
suite.Run(tc.name, func() {
tc.malleate()
consumed := suite.ctx.GasMeter().GasConsumed()
ctx, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(tc.checkTx), tc.tx, false, nextFn)
suite.Require().Equal(consumed, ctx.GasMeter().GasConsumed())
_, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(tc.checkTx), tc.tx, false, nextFn)
if tc.expPass {
suite.Require().NoError(err)
@ -193,9 +187,7 @@ func (suite AnteTestSuite) TestEthNonceVerificationDecorator() {
suite.Run(tc.name, func() {
tc.malleate()
consumed := suite.ctx.GasMeter().GasConsumed()
ctx, err := dec.AnteHandle(suite.ctx.WithIsReCheckTx(tc.reCheckTx), tc.tx, false, nextFn)
suite.Require().Equal(consumed, ctx.GasMeter().GasConsumed())
_, err := dec.AnteHandle(suite.ctx.WithIsReCheckTx(tc.reCheckTx), tc.tx, false, nextFn)
if tc.expPass {
suite.Require().NoError(err)
@ -303,11 +295,9 @@ func (suite AnteTestSuite) TestEthGasConsumeDecorator() {
return
}
consumed := suite.ctx.GasMeter().GasConsumed()
ctx, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(true), tc.tx, false, nextFn)
_, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(true), tc.tx, false, nextFn)
if tc.expPass {
suite.Require().NoError(err)
suite.Require().Equal(int(params.TxGasContractCreation+params.TxAccessListAddressGas), int(ctx.GasMeter().GasConsumed()-consumed))
} else {
suite.Require().Error(err)
}
@ -364,9 +354,7 @@ func (suite AnteTestSuite) TestCanTransferDecorator() {
tc.malleate()
consumed := suite.ctx.GasMeter().GasConsumed()
ctx, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(true), tc.tx, false, nextFn)
suite.Require().Equal(consumed, ctx.GasMeter().GasConsumed())
_, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(true), tc.tx, false, nextFn)
if tc.expPass {
suite.Require().NoError(err)
@ -426,10 +414,7 @@ func (suite AnteTestSuite) TestAccessListDecorator() {
suite.Run(tc.name, func() {
tc.malleate()
consumed := suite.ctx.GasMeter().GasConsumed()
ctx, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(true), tc.tx, false, nextFn)
suite.Require().Equal(consumed, ctx.GasMeter().GasConsumed())
_, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(true), tc.tx, false, nextFn)
if tc.expPass {
suite.Require().NoError(err)
@ -503,7 +488,6 @@ func (suite AnteTestSuite) TestEthIncrementSenderSequenceDecorator() {
suite.Run(tc.name, func() {
tc.malleate()
consumed := suite.ctx.GasMeter().GasConsumed()
if tc.expPanic {
suite.Require().Panics(func() {
@ -512,8 +496,7 @@ func (suite AnteTestSuite) TestEthIncrementSenderSequenceDecorator() {
return
}
ctx, err := dec.AnteHandle(suite.ctx, tc.tx, false, nextFn)
suite.Require().Equal(consumed, ctx.GasMeter().GasConsumed())
_, err := dec.AnteHandle(suite.ctx, tc.tx, false, nextFn)
if tc.expPass {
suite.Require().NoError(err)
@ -530,3 +513,34 @@ func (suite AnteTestSuite) TestEthIncrementSenderSequenceDecorator() {
})
}
}
func (suite AnteTestSuite) TestEthSetupContextDecorator() {
dec := ante.NewEthSetUpContextDecorator()
tx := evmtypes.NewMsgEthereumTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil)
testCases := []struct {
name string
tx sdk.Tx
expPass bool
}{
{"invalid transaction type - does not implement GasTx", &invalidTx{}, false},
{
"success - transaction implement GasTx",
tx,
true,
},
}
for _, tc := range testCases {
suite.Run(tc.name, func() {
_, err := dec.AnteHandle(suite.ctx, tc.tx, false, nextFn)
if tc.expPass {
suite.Require().NoError(err)
} else {
suite.Require().Error(err)
}
})
}
}

View File

@ -827,6 +827,7 @@ MsgEthereumTxResponse defines the Msg/EthereumTx response type.
| `logs` | [Log](#ethermint.evm.v1alpha1.Log) | repeated | logs contains the transaction hash and the proto-compatible ethereum logs. |
| `ret` | [bytes](#bytes) | | returned data from evm function (result or data supplied with revert opcode) |
| `reverted` | [bool](#bool) | | reverted flag is set to true when the call has been reverted |
| `gas_used` | [uint64](#uint64) | | gas consumed by the transaction |

View File

@ -667,11 +667,7 @@ func (e *PublicAPI) EstimateGas(args rpctypes.CallArgs) (hexutil.Uint64, error)
return 0, rpctypes.ErrRevertedWith(data.Ret)
}
// TODO: Add Gas Info from state transition to MsgEthereumTxResponse fields and return that instead
estimatedGas := simRes.GasInfo.GasUsed
gas := estimatedGas + 200000
return hexutil.Uint64(gas), nil
return hexutil.Uint64(data.GasUsed), nil
}
// GetBlockByHash returns the block identified by hash.

View File

@ -52,4 +52,6 @@ message MsgEthereumTxResponse {
bytes ret = 3;
// reverted flag is set to true when the call has been reverted
bool reverted = 4;
// gas consumed by the transaction
uint64 gas_used = 5;
}

View File

@ -112,12 +112,7 @@ func (k Keeper) GetHashFn() vm.GetHashFunc {
func (k *Keeper) ApplyTransaction(tx *ethtypes.Transaction) (*types.MsgEthereumTxResponse, error) {
defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), types.MetricKeyTransitionDB)
gasMeter := k.ctx.GasMeter() // tx gas meter
// ignore gas consumption costs
infCtx := k.ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
cfg, found := k.GetChainConfig(infCtx)
cfg, found := k.GetChainConfig(k.ctx)
if !found {
return nil, stacktrace.Propagate(types.ErrChainConfigNotFound, "configuration not found")
}
@ -135,9 +130,6 @@ func (k *Keeper) ApplyTransaction(tx *ethtypes.Transaction) (*types.MsgEthereumT
k.IncreaseTxIndexTransient()
// set the original gas meter to apply the message and perform the state transition
k.WithContext(k.ctx.WithGasMeter(gasMeter))
// create an ethereum StateTransition instance and run TransitionDb
res, err := k.ApplyMessage(evm, msg, ethCfg)
if err != nil {
@ -157,6 +149,7 @@ func (k *Keeper) ApplyTransaction(tx *ethtypes.Transaction) (*types.MsgEthereumT
bloom.Or(bloom, big.NewInt(0).SetBytes(ethtypes.LogsBloom(logs)))
k.SetBlockBloomTransient(bloom)
k.resetGasMeterAndConsumeGas(res.GasUsed)
return res, nil
}
@ -209,24 +202,13 @@ func (k *Keeper) ApplyMessage(evm *vm.EVM, msg core.Message, cfg *params.ChainCo
sender := vm.AccountRef(msg.From())
contractCreation := msg.To() == nil
// transaction gas meter (tracks limit and usage)
gasConsumed := k.ctx.GasMeter().GasConsumed()
leftoverGas := k.ctx.GasMeter().Limit() - k.ctx.GasMeter().GasConsumedToLimit()
// NOTE: Since CRUD operations on the SDK store consume gas we need to set up an infinite gas meter so that we only consume
// the gas used by the Ethereum message execution.
// Not setting the infinite gas meter here would mean that we are incurring in additional gas costs
k.WithContext(k.ctx.WithGasMeter(sdk.NewInfiniteGasMeter()))
// NOTE: gas limit is the GasLimit defied in the message minus the Intrinsic Gas that has already been
// consumed on the AnteHandler.
// ensure gas is consistent during CheckTx
if k.ctx.IsCheckTx() {
if err := k.CheckGasConsumption(msg, cfg, gasConsumed, contractCreation); err != nil {
return nil, stacktrace.Propagate(err, "gas consumption check failed during CheckTx")
}
intrinsicGas, err := k.GetEthIntrinsicGas(msg, cfg, contractCreation)
if err != nil {
// should have already been checked on Ante Handler
return nil, stacktrace.Propagate(err, "intrinsic gas failed")
}
// should be > 0 as it is checked on Ante Handler
leftoverGas := msg.Gas() - intrinsicGas
if contractCreation {
ret, _, leftoverGas, vmErr = evm.Create(sender, msg.Data(), leftoverGas, msg.Value())
@ -235,7 +217,8 @@ func (k *Keeper) ApplyMessage(evm *vm.EVM, msg core.Message, cfg *params.ChainCo
}
// refund gas prior to handling the vm error in order to set the updated gas meter
if err := k.RefundGas(msg, leftoverGas); err != nil {
leftoverGas, err = k.RefundGas(msg, leftoverGas)
if err != nil {
return nil, stacktrace.Propagate(err, "failed to refund gas leftover gas to sender %s", msg.From())
}
@ -249,38 +232,30 @@ func (k *Keeper) ApplyMessage(evm *vm.EVM, msg core.Message, cfg *params.ChainCo
return nil, stacktrace.Propagate(sdkerrors.Wrap(types.ErrVMExecution, vmErr.Error()), "vm execution failed")
}
gasUsed := msg.Gas() - leftoverGas
return &types.MsgEthereumTxResponse{
Ret: ret,
Reverted: false,
GasUsed: gasUsed,
}, nil
}
// CheckGasConsumption verifies that the amount of gas consumed so far matches the intrinsic gas value.
func (k *Keeper) CheckGasConsumption(msg core.Message, cfg *params.ChainConfig, gasConsumed uint64, isContractCreation bool) error {
// GetEthIntrinsicGas get the transaction intrinsic gas cost
func (k *Keeper) GetEthIntrinsicGas(msg core.Message, cfg *params.ChainConfig, isContractCreation bool) (uint64, error) {
height := big.NewInt(k.ctx.BlockHeight())
homestead := cfg.IsHomestead(height)
istanbul := cfg.IsIstanbul(height)
intrinsicGas, err := core.IntrinsicGas(msg.Data(), msg.AccessList(), isContractCreation, homestead, istanbul)
if err != nil {
// should have already been checked on Ante Handler
return stacktrace.Propagate(err, "intrinsic gas failed")
}
if intrinsicGas != gasConsumed {
return sdkerrors.Wrapf(types.ErrInconsistentGas, "expected gas consumption to be %d (intrinsic gas only), got %d", intrinsicGas, gasConsumed)
}
return nil
return core.IntrinsicGas(msg.Data(), msg.AccessList(), isContractCreation, homestead, istanbul)
}
// RefundGas transfers the leftover gas to the sender of the message, caped to half of the total gas
// consumed in the transaction. Additionally, the function sets the total gas consumed to the value
// returned by the EVM execution, thus ignoring the previous intrinsic gas inconsumed during in the
// returned by the EVM execution, thus ignoring the previous intrinsic gas consumed during in the
// AnteHandler.
func (k *Keeper) RefundGas(msg core.Message, leftoverGas uint64) error {
func (k *Keeper) RefundGas(msg core.Message, leftoverGas uint64) (uint64, error) {
if leftoverGas > msg.Gas() {
return stacktrace.Propagate(
return leftoverGas, stacktrace.Propagate(
sdkerrors.Wrapf(types.ErrInconsistentGas, "leftover gas cannot be greater than gas limit (%d > %d)", leftoverGas, msg.Gas()),
"failed to update gas consumed after refund of leftover gas",
)
@ -298,47 +273,42 @@ func (k *Keeper) RefundGas(msg core.Message, leftoverGas uint64) error {
leftoverGas += refund
if leftoverGas > msg.Gas() {
return stacktrace.Propagate(
return leftoverGas, stacktrace.Propagate(
sdkerrors.Wrapf(types.ErrInconsistentGas, "leftover gas cannot be greater than gas limit (%d > %d)", leftoverGas, msg.Gas()),
"failed to update gas consumed after refund of %d gas", refund,
)
}
gasConsumed = msg.Gas() - leftoverGas
// Return EVM tokens for remaining gas, exchanged at the original rate.
remaining := new(big.Int).Mul(new(big.Int).SetUint64(leftoverGas), msg.GasPrice())
// ignore gas consumption
infCtx := k.ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
switch remaining.Sign() {
case -1:
// negative refund errors
return sdkerrors.Wrapf(types.ErrInvalidRefund, "refunded amount value cannot be negative %d", remaining.Int64())
return leftoverGas, sdkerrors.Wrapf(types.ErrInvalidRefund, "refunded amount value cannot be negative %d", remaining.Int64())
case 1:
// positive amount refund
params := k.GetParams(infCtx)
params := k.GetParams(k.ctx)
refundedCoins := sdk.Coins{sdk.NewCoin(params.EvmDenom, sdk.NewIntFromBigInt(remaining))}
// refund to sender from the fee collector module account, which is the escrow account in charge of collecting tx fees
err := k.bankKeeper.SendCoinsFromModuleToAccount(infCtx, authtypes.FeeCollectorName, msg.From().Bytes(), refundedCoins)
err := k.bankKeeper.SendCoinsFromModuleToAccount(k.ctx, authtypes.FeeCollectorName, msg.From().Bytes(), refundedCoins)
if err != nil {
err = sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, "fee collector account failed to refund fees: %s", err.Error())
return stacktrace.Propagate(err, "failed to refund %d leftover gas (%s)", leftoverGas, refundedCoins.String())
return leftoverGas, stacktrace.Propagate(err, "failed to refund %d leftover gas (%s)", leftoverGas, refundedCoins.String())
}
default:
// no refund, consume gas and update the tx gas meter
}
// set the gas consumed into the context with the new gas meter. This gas meter will have the
// original gas limit defined in the msg and will consume the gas now that the amount has been
// refunded
gasMeter := sdk.NewGasMeter(msg.Gas())
// NOTE: gas consumed will always be less than the limit
gasMeter.ConsumeGas(gasConsumed, "update gas consumption after refund")
k.WithContext(k.ctx.WithGasMeter(gasMeter))
return nil
return leftoverGas, nil
}
// resetGasMeterAndConsumeGas reset first the gas meter consumed value to zero and set it back to the new value
// 'gasUsed'
func (k *Keeper) resetGasMeterAndConsumeGas(gasUsed uint64) {
// reset the gas count
k.ctx.GasMeter().RefundGas(k.ctx.GasMeter().GasConsumed(), "reset the gas count")
k.ctx.GasMeter().ConsumeGas(gasUsed, "apply evm transaction")
}

View File

@ -160,6 +160,8 @@ type MsgEthereumTxResponse struct {
Ret []byte `protobuf:"bytes,3,opt,name=ret,proto3" json:"ret,omitempty"`
// reverted flag is set to true when the call has been reverted
Reverted bool `protobuf:"varint,4,opt,name=reverted,proto3" json:"reverted,omitempty"`
// gas consumed by the transaction
GasUsed uint64 `protobuf:"varint,5,opt,name=gas_used,json=gasUsed,proto3" json:"gas_used,omitempty"`
}
func (m *MsgEthereumTxResponse) Reset() { *m = MsgEthereumTxResponse{} }
@ -205,32 +207,34 @@ func init() {
func init() { proto.RegisterFile("ethermint/evm/v1alpha1/tx.proto", fileDescriptor_6a305e80b084ab0e) }
var fileDescriptor_6a305e80b084ab0e = []byte{
// 400 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0x41, 0xeb, 0xd3, 0x30,
0x18, 0xc6, 0x9b, 0xb5, 0xea, 0xcc, 0x14, 0x24, 0xe8, 0xa8, 0x15, 0xd2, 0x52, 0x10, 0x7a, 0x59,
0xcb, 0xba, 0xdb, 0x8e, 0xc5, 0xdd, 0x1c, 0x42, 0x18, 0x08, 0xde, 0x52, 0x17, 0xdb, 0xc2, 0xda,
0x94, 0x24, 0x2b, 0xd5, 0x4f, 0xe0, 0x71, 0x57, 0x6f, 0x7e, 0x1c, 0x8f, 0x3b, 0x7a, 0x1a, 0xb2,
0xdd, 0x3c, 0xfa, 0x09, 0xa4, 0x99, 0xdb, 0x9c, 0x38, 0xf8, 0xdf, 0xde, 0xf6, 0xfd, 0x25, 0xcf,
0xf3, 0x84, 0x07, 0xba, 0x4c, 0xe5, 0x4c, 0x94, 0x45, 0xa5, 0x22, 0xd6, 0x94, 0x51, 0x33, 0xa6,
0xab, 0x3a, 0xa7, 0xe3, 0x48, 0xb5, 0x61, 0x2d, 0xb8, 0xe2, 0x68, 0x78, 0x06, 0x42, 0xd6, 0x94,
0xe1, 0x09, 0x70, 0x9e, 0x66, 0x3c, 0xe3, 0x1a, 0x89, 0xba, 0xe9, 0x48, 0x3b, 0xde, 0x8d, 0xeb,
0xba, 0xa3, 0x9a, 0xf0, 0xbf, 0x00, 0xf8, 0x78, 0x2e, 0xb3, 0x59, 0xc7, 0xb1, 0x75, 0xb9, 0x68,
0x51, 0x0c, 0xad, 0x25, 0x55, 0xd4, 0x06, 0x1e, 0x08, 0x06, 0x31, 0x0e, 0xff, 0x2f, 0x18, 0x2e,
0xda, 0x57, 0x54, 0x51, 0xa2, 0x59, 0xf4, 0x1c, 0x5a, 0xb2, 0xf8, 0xc4, 0xec, 0x9e, 0x07, 0x02,
0x90, 0xdc, 0xfb, 0xb9, 0x73, 0xc1, 0x88, 0xe8, 0x5f, 0xc8, 0x85, 0x56, 0x4e, 0x65, 0x6e, 0x9b,
0x1e, 0x08, 0x1e, 0x26, 0x83, 0x5f, 0x3b, 0xf7, 0x81, 0x58, 0xd5, 0x53, 0x7f, 0xe4, 0x13, 0xbd,
0x40, 0x08, 0x5a, 0x1f, 0x04, 0x2f, 0x6d, 0xab, 0x03, 0x88, 0x9e, 0xa7, 0xd6, 0xe7, 0xaf, 0xae,
0xe1, 0xfb, 0xd0, 0x99, 0xb5, 0x8a, 0x55, 0xb2, 0xe0, 0xd5, 0x9b, 0x5a, 0x15, 0xbc, 0x92, 0x17,
0x9f, 0x7f, 0x18, 0x0c, 0x87, 0xff, 0x32, 0x6f, 0x59, 0x3a, 0x39, 0xef, 0x37, 0x00, 0x3e, 0xbb,
0xca, 0x47, 0x98, 0xac, 0x79, 0x25, 0x59, 0xa7, 0xab, 0x8d, 0x81, 0xa3, 0xae, 0xf6, 0x12, 0x41,
0x6b, 0xc5, 0x33, 0x69, 0xf7, 0x3c, 0x33, 0x18, 0xc4, 0x2f, 0x6e, 0x65, 0x7f, 0xcd, 0x33, 0xa2,
0x41, 0xf4, 0x04, 0x9a, 0x82, 0x29, 0x1d, 0xee, 0x11, 0xe9, 0x46, 0xe4, 0xc0, 0xbe, 0x60, 0x0d,
0x13, 0x8a, 0x2d, 0x75, 0xa4, 0x3e, 0x39, 0x7f, 0x1f, 0x2d, 0xc5, 0x05, 0x34, 0xe7, 0x32, 0x43,
0x29, 0x84, 0x7f, 0xbd, 0xfa, 0xcb, 0x5b, 0x5a, 0x57, 0xe6, 0x9d, 0xd1, 0x9d, 0xb0, 0x53, 0xc6,
0x24, 0xf9, 0xb6, 0xc7, 0x60, 0xbb, 0xc7, 0xe0, 0xc7, 0x1e, 0x83, 0xcd, 0x01, 0x1b, 0xdb, 0x03,
0x36, 0xbe, 0x1f, 0xb0, 0xf1, 0x2e, 0xc8, 0x0a, 0x95, 0xaf, 0xd3, 0xf0, 0x3d, 0x2f, 0x23, 0x95,
0x53, 0x21, 0x0b, 0x19, 0x5d, 0xca, 0xd2, 0xea, 0xba, 0xa8, 0x8f, 0x35, 0x93, 0xe9, 0x7d, 0x5d,
0x94, 0xc9, 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0x4e, 0x06, 0x55, 0xd8, 0x9b, 0x02, 0x00, 0x00,
// 426 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0x41, 0x8b, 0xd3, 0x40,
0x14, 0xc7, 0x3b, 0xdb, 0xac, 0x5b, 0x5f, 0x15, 0x64, 0xd0, 0x25, 0x1b, 0x21, 0x09, 0x01, 0x21,
0x97, 0x26, 0x6c, 0xf7, 0xb6, 0xc7, 0xe2, 0xde, 0x5c, 0x84, 0x61, 0x45, 0xf0, 0x22, 0x53, 0xfb,
0x9c, 0x04, 0x9a, 0x4c, 0x98, 0x37, 0x2d, 0xd1, 0x4f, 0xe0, 0xd1, 0xab, 0x37, 0xef, 0x7e, 0x11,
0x8f, 0x7b, 0xf4, 0xb4, 0x48, 0x7b, 0xf3, 0xe8, 0x27, 0x90, 0x4c, 0xdd, 0xae, 0x2b, 0x16, 0xbc,
0xbd, 0xe4, 0xfd, 0x66, 0xde, 0xff, 0xc7, 0x3c, 0x88, 0xd0, 0x16, 0x68, 0xaa, 0xb2, 0xb6, 0x39,
0x2e, 0xab, 0x7c, 0x79, 0x2c, 0xe7, 0x4d, 0x21, 0x8f, 0x73, 0xdb, 0x66, 0x8d, 0xd1, 0x56, 0xf3,
0xc3, 0x2d, 0x90, 0xe1, 0xb2, 0xca, 0xae, 0x81, 0xe0, 0xa1, 0xd2, 0x4a, 0x3b, 0x24, 0xef, 0xaa,
0x0d, 0x1d, 0xc4, 0x3b, 0xae, 0xeb, 0x8e, 0x3a, 0x22, 0xf9, 0xc4, 0xe0, 0xfe, 0x39, 0xa9, 0xb3,
0x8e, 0xc3, 0x45, 0x75, 0xd1, 0xf2, 0x31, 0x78, 0x33, 0x69, 0xa5, 0xcf, 0x62, 0x96, 0x0e, 0xc7,
0x61, 0xf6, 0xef, 0x81, 0xd9, 0x45, 0xfb, 0x54, 0x5a, 0x29, 0x1c, 0xcb, 0x8f, 0xc0, 0xa3, 0xf2,
0x3d, 0xfa, 0x7b, 0x31, 0x4b, 0xd9, 0x64, 0xff, 0xc7, 0x55, 0xc4, 0x46, 0xc2, 0xfd, 0xe2, 0x11,
0x78, 0x85, 0xa4, 0xc2, 0xef, 0xc7, 0x2c, 0xbd, 0x3b, 0x19, 0xfe, 0xbc, 0x8a, 0x0e, 0xcc, 0xbc,
0x39, 0x4d, 0x46, 0x89, 0x70, 0x0d, 0xce, 0xc1, 0x7b, 0x6b, 0x74, 0xe5, 0x7b, 0x1d, 0x20, 0x5c,
0x7d, 0xea, 0x7d, 0xf8, 0x1c, 0xf5, 0x92, 0x04, 0x82, 0xb3, 0xd6, 0x62, 0x4d, 0xa5, 0xae, 0x9f,
0x37, 0xb6, 0xd4, 0x35, 0xdd, 0xe4, 0xfc, 0xcd, 0x84, 0x70, 0xf8, 0x37, 0xf3, 0x12, 0xa7, 0x27,
0xdb, 0xfe, 0x17, 0x06, 0x8f, 0x6e, 0xf9, 0x09, 0xa4, 0x46, 0xd7, 0x84, 0xdd, 0x5c, 0x17, 0x8c,
0x6d, 0xe6, 0xba, 0x2c, 0x39, 0x78, 0x73, 0xad, 0xc8, 0xdf, 0x8b, 0xfb, 0xe9, 0x70, 0xfc, 0x78,
0x97, 0xfb, 0x33, 0xad, 0x84, 0x03, 0xf9, 0x03, 0xe8, 0x1b, 0xb4, 0x4e, 0xee, 0x9e, 0xe8, 0x4a,
0x1e, 0xc0, 0xc0, 0xe0, 0x12, 0x8d, 0xc5, 0x99, 0x53, 0x1a, 0x88, 0xed, 0x37, 0x3f, 0x82, 0x81,
0x92, 0xf4, 0x7a, 0x41, 0x38, 0xf3, 0xf7, 0x63, 0x96, 0x7a, 0xe2, 0x40, 0x49, 0x7a, 0x41, 0x38,
0xdb, 0xa4, 0x1d, 0x97, 0xd0, 0x3f, 0x27, 0xc5, 0xa7, 0x00, 0x7f, 0x3c, 0xc8, 0x93, 0x5d, 0x31,
0x6e, 0x79, 0x05, 0xa3, 0xff, 0xc2, 0xae, 0xf5, 0x27, 0x93, 0xaf, 0xab, 0x90, 0x5d, 0xae, 0x42,
0xf6, 0x7d, 0x15, 0xb2, 0x8f, 0xeb, 0xb0, 0x77, 0xb9, 0x0e, 0x7b, 0xdf, 0xd6, 0x61, 0xef, 0x55,
0xaa, 0x4a, 0x5b, 0x2c, 0xa6, 0xd9, 0x1b, 0x5d, 0xe5, 0xb6, 0x90, 0x86, 0x4a, 0xca, 0x6f, 0xf6,
0xa8, 0x75, 0x9b, 0x64, 0xdf, 0x35, 0x48, 0xd3, 0x3b, 0x6e, 0x87, 0x4e, 0x7e, 0x05, 0x00, 0x00,
0xff, 0xff, 0x0f, 0x24, 0xe9, 0xff, 0xb6, 0x02, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
@ -436,6 +440,11 @@ func (m *MsgEthereumTxResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) {
_ = i
var l int
_ = l
if m.GasUsed != 0 {
i = encodeVarintTx(dAtA, i, uint64(m.GasUsed))
i--
dAtA[i] = 0x28
}
if m.Reverted {
i--
if m.Reverted {
@ -553,6 +562,9 @@ func (m *MsgEthereumTxResponse) Size() (n int) {
if m.Reverted {
n += 2
}
if m.GasUsed != 0 {
n += 1 + sovTx(uint64(m.GasUsed))
}
return n
}
@ -981,6 +993,25 @@ func (m *MsgEthereumTxResponse) Unmarshal(dAtA []byte) error {
}
}
m.Reverted = bool(v != 0)
case 5:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field GasUsed", wireType)
}
m.GasUsed = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTx
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.GasUsed |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
default:
iNdEx = preIndex
skippy, err := skipTx(dAtA[iNdEx:])