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 // handle as *evmtypes.MsgEthereumTx
anteHandler = sdk.ChainAnteDecorators( anteHandler = sdk.ChainAnteDecorators(
authante.NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first NewEthSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first
authante.NewMempoolFeeDecorator(), authante.NewMempoolFeeDecorator(),
authante.NewTxTimeoutHeightDecorator(), authante.NewTxTimeoutHeightDecorator(),
authante.NewValidateMemoDecorator(ak), 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() chainID := esvd.evmKeeper.ChainID()
config, found := esvd.evmKeeper.GetChainConfig(infCtx) config, found := esvd.evmKeeper.GetChainConfig(ctx)
if !found { if !found {
return ctx, evmtypes.ErrChainConfigNotFound return ctx, evmtypes.ErrChainConfigNotFound
} }
@ -122,11 +118,8 @@ func (avd EthAccountVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx
return next(ctx, tx, simulate) return next(ctx, tx, simulate)
} }
// get and set account must be called with an infinite gas meter in order to prevent avd.evmKeeper.WithContext(ctx)
// additional gas from being deducted. evmDenom := avd.evmKeeper.GetParams(ctx).EvmDenom
infCtx := ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
avd.evmKeeper.WithContext(infCtx)
evmDenom := avd.evmKeeper.GetParams(infCtx).EvmDenom
for i, msg := range tx.GetMsgs() { for i, msg := range tx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx) 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), "") "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 { if acc == nil {
acc = avd.ak.NewAccountWithAddress(infCtx, from) acc = avd.ak.NewAccountWithAddress(ctx, from)
avd.ak.SetAccount(infCtx, acc) avd.ak.SetAccount(ctx, acc)
} }
// validate sender has enough funds to pay for tx cost // 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 { if balance.Amount.BigInt().Cmp(msgEthTx.Cost()) < 0 {
return ctx, stacktrace.Propagate( return ctx, stacktrace.Propagate(
sdkerrors.Wrapf( sdkerrors.Wrapf(
@ -199,10 +192,6 @@ func (nvd EthNonceVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx,
return next(ctx, tx, simulate) 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() { for i, msg := range tx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx) msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok { 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 // 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 { if err != nil {
return ctx, stacktrace.Propagate(err, "sequence not found for address %s", msgEthTx.From) 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) // - user doesn't have enough balance to deduct the transaction fees (gas_limit * gas_price)
// - transaction or block gas meter runs out of gas // - 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) { 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 // 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 { if !found {
return ctx, evmtypes.ErrChainConfigNotFound return ctx, evmtypes.ErrChainConfigNotFound
} }
@ -297,7 +282,7 @@ func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula
isContractCreation := msgEthTx.To() == nil isContractCreation := msgEthTx.To() == nil
// fetch sender account from signature // 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 { if err != nil {
return ctx, stacktrace.Propagate(err, "account not found for sender %s", msgEthTx.From) 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 // calculate the fees paid to validators based on gas limit and price
feeAmt := msgEthTx.Fee() // fee = gas limit * gas 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))} fees := sdk.Coins{sdk.NewCoin(evmDenom, sdk.NewIntFromBigInt(feeAmt))}
// deduct the full gas cost from the user balance // 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( return ctx, stacktrace.Propagate(
err, err,
"failed to deduct full gas cost %s from the user %s balance", fees, msgEthTx.From, "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 // 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 // AnteHandle creates an EVM from the message and calls the BlockContext CanTransfer function to
// see if the address can execute the transaction. // 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) { 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 ctd.evmKeeper.WithContext(ctx)
// additional gas from being deducted.
infCtx := ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
ctd.evmKeeper.WithContext(infCtx)
config, found := ctd.evmKeeper.GetChainConfig(infCtx) config, found := ctd.evmKeeper.GetChainConfig(ctx)
if !found { if !found {
return ctx, evmtypes.ErrChainConfigNotFound 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. // 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) { 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(ctx)
config, found := ald.evmKeeper.GetChainConfig(infCtx)
if !found { if !found {
return ctx, evmtypes.ErrChainConfigNotFound 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 // setup the keeper context before setting the access list
ald.evmKeeper.WithContext(infCtx) ald.evmKeeper.WithContext(ctx)
for i, msg := range tx.GetMsgs() { for i, msg := range tx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx) 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 // contract creation, the nonce will be incremented during the transaction execution and not within
// this AnteHandler decorator. // this AnteHandler decorator.
func (issd EthIncrementSenderSequenceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { 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() { for i, msg := range tx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx) msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
@ -524,7 +495,7 @@ func (issd EthIncrementSenderSequenceDecorator) AnteHandle(ctx sdk.Context, tx s
// increment sequence of all signers // increment sequence of all signers
for _, addr := range msg.GetSigners() { for _, addr := range msg.GetSigners() {
acc := issd.ak.GetAccount(infCtx, addr) acc := issd.ak.GetAccount(ctx, addr)
if acc == nil { if acc == nil {
return ctx, stacktrace.Propagate( 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) 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) 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" "github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types" 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) { func nextFn(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) {
@ -46,9 +45,7 @@ func (suite AnteTestSuite) TestEthSigVerificationDecorator() {
for _, tc := range testCases { for _, tc := range testCases {
suite.Run(tc.name, func() { suite.Run(tc.name, func() {
consumed := suite.ctx.GasMeter().GasConsumed() _, err := dec.AnteHandle(suite.ctx.WithIsReCheckTx(tc.reCheckTx), tc.tx, false, nextFn)
ctx, err := dec.AnteHandle(suite.ctx.WithIsReCheckTx(tc.reCheckTx), tc.tx, false, nextFn)
suite.Require().Equal(consumed, ctx.GasMeter().GasConsumed())
if tc.expPass { if tc.expPass {
suite.Require().NoError(err) suite.Require().NoError(err)
@ -133,10 +130,7 @@ func (suite AnteTestSuite) TestNewEthAccountVerificationDecorator() {
for _, tc := range testCases { for _, tc := range testCases {
suite.Run(tc.name, func() { suite.Run(tc.name, func() {
tc.malleate() tc.malleate()
_, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(tc.checkTx), tc.tx, false, nextFn)
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())
if tc.expPass { if tc.expPass {
suite.Require().NoError(err) suite.Require().NoError(err)
@ -193,9 +187,7 @@ func (suite AnteTestSuite) TestEthNonceVerificationDecorator() {
suite.Run(tc.name, func() { suite.Run(tc.name, func() {
tc.malleate() tc.malleate()
consumed := suite.ctx.GasMeter().GasConsumed() _, err := dec.AnteHandle(suite.ctx.WithIsReCheckTx(tc.reCheckTx), tc.tx, false, nextFn)
ctx, err := dec.AnteHandle(suite.ctx.WithIsReCheckTx(tc.reCheckTx), tc.tx, false, nextFn)
suite.Require().Equal(consumed, ctx.GasMeter().GasConsumed())
if tc.expPass { if tc.expPass {
suite.Require().NoError(err) suite.Require().NoError(err)
@ -303,11 +295,9 @@ func (suite AnteTestSuite) TestEthGasConsumeDecorator() {
return return
} }
consumed := suite.ctx.GasMeter().GasConsumed() _, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(true), tc.tx, false, nextFn)
ctx, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(true), tc.tx, false, nextFn)
if tc.expPass { if tc.expPass {
suite.Require().NoError(err) suite.Require().NoError(err)
suite.Require().Equal(int(params.TxGasContractCreation+params.TxAccessListAddressGas), int(ctx.GasMeter().GasConsumed()-consumed))
} else { } else {
suite.Require().Error(err) suite.Require().Error(err)
} }
@ -364,9 +354,7 @@ func (suite AnteTestSuite) TestCanTransferDecorator() {
tc.malleate() tc.malleate()
consumed := suite.ctx.GasMeter().GasConsumed() _, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(true), tc.tx, false, nextFn)
ctx, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(true), tc.tx, false, nextFn)
suite.Require().Equal(consumed, ctx.GasMeter().GasConsumed())
if tc.expPass { if tc.expPass {
suite.Require().NoError(err) suite.Require().NoError(err)
@ -426,10 +414,7 @@ func (suite AnteTestSuite) TestAccessListDecorator() {
suite.Run(tc.name, func() { suite.Run(tc.name, func() {
tc.malleate() tc.malleate()
_, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(true), tc.tx, false, nextFn)
consumed := suite.ctx.GasMeter().GasConsumed()
ctx, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(true), tc.tx, false, nextFn)
suite.Require().Equal(consumed, ctx.GasMeter().GasConsumed())
if tc.expPass { if tc.expPass {
suite.Require().NoError(err) suite.Require().NoError(err)
@ -503,7 +488,6 @@ func (suite AnteTestSuite) TestEthIncrementSenderSequenceDecorator() {
suite.Run(tc.name, func() { suite.Run(tc.name, func() {
tc.malleate() tc.malleate()
consumed := suite.ctx.GasMeter().GasConsumed()
if tc.expPanic { if tc.expPanic {
suite.Require().Panics(func() { suite.Require().Panics(func() {
@ -512,8 +496,7 @@ func (suite AnteTestSuite) TestEthIncrementSenderSequenceDecorator() {
return return
} }
ctx, err := dec.AnteHandle(suite.ctx, tc.tx, false, nextFn) _, err := dec.AnteHandle(suite.ctx, tc.tx, false, nextFn)
suite.Require().Equal(consumed, ctx.GasMeter().GasConsumed())
if tc.expPass { if tc.expPass {
suite.Require().NoError(err) 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. | | `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) | | `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 | | `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) return 0, rpctypes.ErrRevertedWith(data.Ret)
} }
// TODO: Add Gas Info from state transition to MsgEthereumTxResponse fields and return that instead return hexutil.Uint64(data.GasUsed), nil
estimatedGas := simRes.GasInfo.GasUsed
gas := estimatedGas + 200000
return hexutil.Uint64(gas), nil
} }
// GetBlockByHash returns the block identified by hash. // GetBlockByHash returns the block identified by hash.

View File

@ -52,4 +52,6 @@ message MsgEthereumTxResponse {
bytes ret = 3; bytes ret = 3;
// reverted flag is set to true when the call has been reverted // reverted flag is set to true when the call has been reverted
bool reverted = 4; 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) { func (k *Keeper) ApplyTransaction(tx *ethtypes.Transaction) (*types.MsgEthereumTxResponse, error) {
defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), types.MetricKeyTransitionDB) defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), types.MetricKeyTransitionDB)
gasMeter := k.ctx.GasMeter() // tx gas meter cfg, found := k.GetChainConfig(k.ctx)
// ignore gas consumption costs
infCtx := k.ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
cfg, found := k.GetChainConfig(infCtx)
if !found { if !found {
return nil, stacktrace.Propagate(types.ErrChainConfigNotFound, "configuration not 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() 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 // create an ethereum StateTransition instance and run TransitionDb
res, err := k.ApplyMessage(evm, msg, ethCfg) res, err := k.ApplyMessage(evm, msg, ethCfg)
if err != nil { 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))) bloom.Or(bloom, big.NewInt(0).SetBytes(ethtypes.LogsBloom(logs)))
k.SetBlockBloomTransient(bloom) k.SetBlockBloomTransient(bloom)
k.resetGasMeterAndConsumeGas(res.GasUsed)
return res, nil 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()) sender := vm.AccountRef(msg.From())
contractCreation := msg.To() == nil contractCreation := msg.To() == nil
// transaction gas meter (tracks limit and usage) intrinsicGas, err := k.GetEthIntrinsicGas(msg, cfg, contractCreation)
gasConsumed := k.ctx.GasMeter().GasConsumed() if err != nil {
leftoverGas := k.ctx.GasMeter().Limit() - k.ctx.GasMeter().GasConsumedToLimit() // should have already been checked on Ante Handler
return nil, stacktrace.Propagate(err, "intrinsic gas failed")
// 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")
}
} }
// should be > 0 as it is checked on Ante Handler
leftoverGas := msg.Gas() - intrinsicGas
if contractCreation { if contractCreation {
ret, _, leftoverGas, vmErr = evm.Create(sender, msg.Data(), leftoverGas, msg.Value()) 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 // 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()) 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") return nil, stacktrace.Propagate(sdkerrors.Wrap(types.ErrVMExecution, vmErr.Error()), "vm execution failed")
} }
gasUsed := msg.Gas() - leftoverGas
return &types.MsgEthereumTxResponse{ return &types.MsgEthereumTxResponse{
Ret: ret, Ret: ret,
Reverted: false, Reverted: false,
GasUsed: gasUsed,
}, nil }, nil
} }
// CheckGasConsumption verifies that the amount of gas consumed so far matches the intrinsic gas value. // GetEthIntrinsicGas get the transaction intrinsic gas cost
func (k *Keeper) CheckGasConsumption(msg core.Message, cfg *params.ChainConfig, gasConsumed uint64, isContractCreation bool) error { func (k *Keeper) GetEthIntrinsicGas(msg core.Message, cfg *params.ChainConfig, isContractCreation bool) (uint64, error) {
height := big.NewInt(k.ctx.BlockHeight()) height := big.NewInt(k.ctx.BlockHeight())
homestead := cfg.IsHomestead(height) homestead := cfg.IsHomestead(height)
istanbul := cfg.IsIstanbul(height) istanbul := cfg.IsIstanbul(height)
intrinsicGas, err := core.IntrinsicGas(msg.Data(), msg.AccessList(), isContractCreation, homestead, istanbul) return 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
} }
// RefundGas transfers the leftover gas to the sender of the message, caped to half of the total gas // 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 // 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. // 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() { 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()), 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", "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 leftoverGas += refund
if leftoverGas > msg.Gas() { 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()), 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, "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. // Return EVM tokens for remaining gas, exchanged at the original rate.
remaining := new(big.Int).Mul(new(big.Int).SetUint64(leftoverGas), msg.GasPrice()) remaining := new(big.Int).Mul(new(big.Int).SetUint64(leftoverGas), msg.GasPrice())
// ignore gas consumption
infCtx := k.ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
switch remaining.Sign() { switch remaining.Sign() {
case -1: case -1:
// negative refund errors // 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: case 1:
// positive amount refund // positive amount refund
params := k.GetParams(infCtx) params := k.GetParams(k.ctx)
refundedCoins := sdk.Coins{sdk.NewCoin(params.EvmDenom, sdk.NewIntFromBigInt(remaining))} 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 // 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 { if err != nil {
err = sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, "fee collector account failed to refund fees: %s", err.Error()) 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: default:
// no refund, consume gas and update the tx gas meter // 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 return leftoverGas, nil
// original gas limit defined in the msg and will consume the gas now that the amount has been }
// refunded
gasMeter := sdk.NewGasMeter(msg.Gas()) // resetGasMeterAndConsumeGas reset first the gas meter consumed value to zero and set it back to the new value
// NOTE: gas consumed will always be less than the limit // 'gasUsed'
gasMeter.ConsumeGas(gasConsumed, "update gas consumption after refund") func (k *Keeper) resetGasMeterAndConsumeGas(gasUsed uint64) {
k.WithContext(k.ctx.WithGasMeter(gasMeter)) // reset the gas count
k.ctx.GasMeter().RefundGas(k.ctx.GasMeter().GasConsumed(), "reset the gas count")
return nil 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"` 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 flag is set to true when the call has been reverted
Reverted bool `protobuf:"varint,4,opt,name=reverted,proto3" json:"reverted,omitempty"` 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{} } func (m *MsgEthereumTxResponse) Reset() { *m = MsgEthereumTxResponse{} }
@ -205,32 +207,34 @@ func init() {
func init() { proto.RegisterFile("ethermint/evm/v1alpha1/tx.proto", fileDescriptor_6a305e80b084ab0e) } func init() { proto.RegisterFile("ethermint/evm/v1alpha1/tx.proto", fileDescriptor_6a305e80b084ab0e) }
var fileDescriptor_6a305e80b084ab0e = []byte{ var fileDescriptor_6a305e80b084ab0e = []byte{
// 400 bytes of a gzipped FileDescriptorProto // 426 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0x41, 0xeb, 0xd3, 0x30, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0x41, 0x8b, 0xd3, 0x40,
0x18, 0xc6, 0x9b, 0xb5, 0xea, 0xcc, 0x14, 0x24, 0xe8, 0xa8, 0x15, 0xd2, 0x52, 0x10, 0x7a, 0x59, 0x14, 0xc7, 0x3b, 0xdb, 0xac, 0x5b, 0x5f, 0x15, 0x64, 0xd0, 0x25, 0x1b, 0x21, 0x09, 0x01, 0x21,
0xcb, 0xba, 0xdb, 0x8e, 0xc5, 0xdd, 0x1c, 0x42, 0x18, 0x08, 0xde, 0x52, 0x17, 0xdb, 0xc2, 0xda, 0x97, 0x26, 0x6c, 0xf7, 0xb6, 0xc7, 0xe2, 0xde, 0x5c, 0x84, 0x61, 0x45, 0xf0, 0x22, 0x53, 0xfb,
0x94, 0x24, 0x2b, 0xd5, 0x4f, 0xe0, 0x71, 0x57, 0x6f, 0x7e, 0x1c, 0x8f, 0x3b, 0x7a, 0x1a, 0xb2, 0x9c, 0x04, 0x9a, 0x4c, 0x98, 0x37, 0x2d, 0xd1, 0x4f, 0xe0, 0xd1, 0xab, 0x37, 0xef, 0x7e, 0x11,
0xdd, 0x3c, 0xfa, 0x09, 0xa4, 0x99, 0xdb, 0x9c, 0x38, 0xf8, 0xdf, 0xde, 0xf6, 0xfd, 0x25, 0xcf, 0x8f, 0x7b, 0xf4, 0xb4, 0x48, 0x7b, 0xf3, 0xe8, 0x27, 0x90, 0x4c, 0xdd, 0xae, 0x2b, 0x16, 0xbc,
0xf3, 0x84, 0x07, 0xba, 0x4c, 0xe5, 0x4c, 0x94, 0x45, 0xa5, 0x22, 0xd6, 0x94, 0x51, 0x33, 0xa6, 0xbd, 0xe4, 0xfd, 0x66, 0xde, 0xff, 0xc7, 0x3c, 0x88, 0xd0, 0x16, 0x68, 0xaa, 0xb2, 0xb6, 0x39,
0xab, 0x3a, 0xa7, 0xe3, 0x48, 0xb5, 0x61, 0x2d, 0xb8, 0xe2, 0x68, 0x78, 0x06, 0x42, 0xd6, 0x94, 0x2e, 0xab, 0x7c, 0x79, 0x2c, 0xe7, 0x4d, 0x21, 0x8f, 0x73, 0xdb, 0x66, 0x8d, 0xd1, 0x56, 0xf3,
0xe1, 0x09, 0x70, 0x9e, 0x66, 0x3c, 0xe3, 0x1a, 0x89, 0xba, 0xe9, 0x48, 0x3b, 0xde, 0x8d, 0xeb, 0xc3, 0x2d, 0x90, 0xe1, 0xb2, 0xca, 0xae, 0x81, 0xe0, 0xa1, 0xd2, 0x4a, 0x3b, 0x24, 0xef, 0xaa,
0xba, 0xa3, 0x9a, 0xf0, 0xbf, 0x00, 0xf8, 0x78, 0x2e, 0xb3, 0x59, 0xc7, 0xb1, 0x75, 0xb9, 0x68, 0x0d, 0x1d, 0xc4, 0x3b, 0xae, 0xeb, 0x8e, 0x3a, 0x22, 0xf9, 0xc4, 0xe0, 0xfe, 0x39, 0xa9, 0xb3,
0x51, 0x0c, 0xad, 0x25, 0x55, 0xd4, 0x06, 0x1e, 0x08, 0x06, 0x31, 0x0e, 0xff, 0x2f, 0x18, 0x2e, 0x8e, 0xc3, 0x45, 0x75, 0xd1, 0xf2, 0x31, 0x78, 0x33, 0x69, 0xa5, 0xcf, 0x62, 0x96, 0x0e, 0xc7,
0xda, 0x57, 0x54, 0x51, 0xa2, 0x59, 0xf4, 0x1c, 0x5a, 0xb2, 0xf8, 0xc4, 0xec, 0x9e, 0x07, 0x02, 0x61, 0xf6, 0xef, 0x81, 0xd9, 0x45, 0xfb, 0x54, 0x5a, 0x29, 0x1c, 0xcb, 0x8f, 0xc0, 0xa3, 0xf2,
0x90, 0xdc, 0xfb, 0xb9, 0x73, 0xc1, 0x88, 0xe8, 0x5f, 0xc8, 0x85, 0x56, 0x4e, 0x65, 0x6e, 0x9b, 0x3d, 0xfa, 0x7b, 0x31, 0x4b, 0xd9, 0x64, 0xff, 0xc7, 0x55, 0xc4, 0x46, 0xc2, 0xfd, 0xe2, 0x11,
0x1e, 0x08, 0x1e, 0x26, 0x83, 0x5f, 0x3b, 0xf7, 0x81, 0x58, 0xd5, 0x53, 0x7f, 0xe4, 0x13, 0xbd, 0x78, 0x85, 0xa4, 0xc2, 0xef, 0xc7, 0x2c, 0xbd, 0x3b, 0x19, 0xfe, 0xbc, 0x8a, 0x0e, 0xcc, 0xbc,
0x40, 0x08, 0x5a, 0x1f, 0x04, 0x2f, 0x6d, 0xab, 0x03, 0x88, 0x9e, 0xa7, 0xd6, 0xe7, 0xaf, 0xae, 0x39, 0x4d, 0x46, 0x89, 0x70, 0x0d, 0xce, 0xc1, 0x7b, 0x6b, 0x74, 0xe5, 0x7b, 0x1d, 0x20, 0x5c,
0xe1, 0xfb, 0xd0, 0x99, 0xb5, 0x8a, 0x55, 0xb2, 0xe0, 0xd5, 0x9b, 0x5a, 0x15, 0xbc, 0x92, 0x17, 0x7d, 0xea, 0x7d, 0xf8, 0x1c, 0xf5, 0x92, 0x04, 0x82, 0xb3, 0xd6, 0x62, 0x4d, 0xa5, 0xae, 0x9f,
0x9f, 0x7f, 0x18, 0x0c, 0x87, 0xff, 0x32, 0x6f, 0x59, 0x3a, 0x39, 0xef, 0x37, 0x00, 0x3e, 0xbb, 0x37, 0xb6, 0xd4, 0x35, 0xdd, 0xe4, 0xfc, 0xcd, 0x84, 0x70, 0xf8, 0x37, 0xf3, 0x12, 0xa7, 0x27,
0xca, 0x47, 0x98, 0xac, 0x79, 0x25, 0x59, 0xa7, 0xab, 0x8d, 0x81, 0xa3, 0xae, 0xf6, 0x12, 0x41, 0xdb, 0xfe, 0x17, 0x06, 0x8f, 0x6e, 0xf9, 0x09, 0xa4, 0x46, 0xd7, 0x84, 0xdd, 0x5c, 0x17, 0x8c,
0x6b, 0xc5, 0x33, 0x69, 0xf7, 0x3c, 0x33, 0x18, 0xc4, 0x2f, 0x6e, 0x65, 0x7f, 0xcd, 0x33, 0xa2, 0x6d, 0xe6, 0xba, 0x2c, 0x39, 0x78, 0x73, 0xad, 0xc8, 0xdf, 0x8b, 0xfb, 0xe9, 0x70, 0xfc, 0x78,
0x41, 0xf4, 0x04, 0x9a, 0x82, 0x29, 0x1d, 0xee, 0x11, 0xe9, 0x46, 0xe4, 0xc0, 0xbe, 0x60, 0x0d, 0x97, 0xfb, 0x33, 0xad, 0x84, 0x03, 0xf9, 0x03, 0xe8, 0x1b, 0xb4, 0x4e, 0xee, 0x9e, 0xe8, 0x4a,
0x13, 0x8a, 0x2d, 0x75, 0xa4, 0x3e, 0x39, 0x7f, 0x1f, 0x2d, 0xc5, 0x05, 0x34, 0xe7, 0x32, 0x43, 0x1e, 0xc0, 0xc0, 0xe0, 0x12, 0x8d, 0xc5, 0x99, 0x53, 0x1a, 0x88, 0xed, 0x37, 0x3f, 0x82, 0x81,
0x29, 0x84, 0x7f, 0xbd, 0xfa, 0xcb, 0x5b, 0x5a, 0x57, 0xe6, 0x9d, 0xd1, 0x9d, 0xb0, 0x53, 0xc6, 0x92, 0xf4, 0x7a, 0x41, 0x38, 0xf3, 0xf7, 0x63, 0x96, 0x7a, 0xe2, 0x40, 0x49, 0x7a, 0x41, 0x38,
0x24, 0xf9, 0xb6, 0xc7, 0x60, 0xbb, 0xc7, 0xe0, 0xc7, 0x1e, 0x83, 0xcd, 0x01, 0x1b, 0xdb, 0x03, 0xdb, 0xa4, 0x1d, 0x97, 0xd0, 0x3f, 0x27, 0xc5, 0xa7, 0x00, 0x7f, 0x3c, 0xc8, 0x93, 0x5d, 0x31,
0x36, 0xbe, 0x1f, 0xb0, 0xf1, 0x2e, 0xc8, 0x0a, 0x95, 0xaf, 0xd3, 0xf0, 0x3d, 0x2f, 0x23, 0x95, 0x6e, 0x79, 0x05, 0xa3, 0xff, 0xc2, 0xae, 0xf5, 0x27, 0x93, 0xaf, 0xab, 0x90, 0x5d, 0xae, 0x42,
0x53, 0x21, 0x0b, 0x19, 0x5d, 0xca, 0xd2, 0xea, 0xba, 0xa8, 0x8f, 0x35, 0x93, 0xe9, 0x7d, 0x5d, 0xf6, 0x7d, 0x15, 0xb2, 0x8f, 0xeb, 0xb0, 0x77, 0xb9, 0x0e, 0x7b, 0xdf, 0xd6, 0x61, 0xef, 0x55,
0x94, 0xc9, 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0x4e, 0x06, 0x55, 0xd8, 0x9b, 0x02, 0x00, 0x00, 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. // Reference imports to suppress errors if they are not otherwise used.
@ -436,6 +440,11 @@ func (m *MsgEthereumTxResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) {
_ = i _ = i
var l int var l int
_ = l _ = l
if m.GasUsed != 0 {
i = encodeVarintTx(dAtA, i, uint64(m.GasUsed))
i--
dAtA[i] = 0x28
}
if m.Reverted { if m.Reverted {
i-- i--
if m.Reverted { if m.Reverted {
@ -553,6 +562,9 @@ func (m *MsgEthereumTxResponse) Size() (n int) {
if m.Reverted { if m.Reverted {
n += 2 n += 2
} }
if m.GasUsed != 0 {
n += 1 + sovTx(uint64(m.GasUsed))
}
return n return n
} }
@ -981,6 +993,25 @@ func (m *MsgEthereumTxResponse) Unmarshal(dAtA []byte) error {
} }
} }
m.Reverted = bool(v != 0) 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: default:
iNdEx = preIndex iNdEx = preIndex
skippy, err := skipTx(dAtA[iNdEx:]) skippy, err := skipTx(dAtA[iNdEx:])