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 05:31:30 -04:00
committed by GitHub
parent 036ffb7a39
commit 5ba8ffe669
8 changed files with 169 additions and 165 deletions
+1 -1
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),
+38 -48
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)
}
+38 -24
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)
}
})
}
}