fix AnteHandler gas consumption (#275)

* fix antehandler gas consumption

* fix gas

* typo
This commit is contained in:
Federico Kunze 2020-05-04 18:41:17 -04:00 committed by GitHub
parent ce0feb307b
commit a99fbfdc2b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 38 additions and 29 deletions

View File

@ -55,7 +55,7 @@ func (suite *AnteTestSuite) TestValidEthTx() {
to := ethcmn.BytesToAddress(addr2.Bytes()) to := ethcmn.BytesToAddress(addr2.Bytes())
amt := big.NewInt(32) amt := big.NewInt(32)
gas := big.NewInt(20) gas := big.NewInt(20)
ethMsg := evmtypes.NewMsgEthereumTx(0, &to, amt, 34910, gas, []byte("test")) ethMsg := evmtypes.NewMsgEthereumTx(0, &to, amt, 22000, gas, []byte("test"))
tx, err := newTestEthTx(suite.ctx, ethMsg, priv1) tx, err := newTestEthTx(suite.ctx, ethMsg, priv1)
suite.Require().NoError(err) suite.Require().NoError(err)

View File

@ -94,16 +94,17 @@ func (emfd EthMempoolFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula
minGasPrices := ctx.MinGasPrices() minGasPrices := ctx.MinGasPrices()
allGTE := true // check that fee provided is greater than the minimum
for _, v := range minGasPrices { // NOTE: we only check if photons are present in min gas prices. It is up to the
if !fee.IsGTE(v) { // sender if they want to send additional fees in other denominations.
allGTE = false var hasEnoughFees bool
} if fee.Amount.GTE(minGasPrices.AmountOf(emint.DenomDefault)) {
hasEnoughFees = true
} }
// it is assumed that the minimum fees will only include the single valid denom // reject transaction if minimum gas price is positive and the transaction does not
if !ctx.MinGasPrices().IsZero() && !allGTE { // meet the minimum fee
// reject the transaction that does not meet the minimum fee if !ctx.MinGasPrices().IsZero() && !hasEnoughFees {
return ctx, sdkerrors.Wrap( return ctx, sdkerrors.Wrap(
sdkerrors.ErrInsufficientFee, sdkerrors.ErrInsufficientFee,
fmt.Sprintf("insufficient fee, got: %q required: %q", fee, ctx.MinGasPrices()), fmt.Sprintf("insufficient fee, got: %q required: %q", fee, ctx.MinGasPrices()),
@ -135,12 +136,14 @@ func (esvd EthSigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, s
} }
// validate sender/signature // validate sender/signature
// NOTE: signer is retrieved from the transaction on the next AnteDecorator
_, err = msgEthTx.VerifySig(chainID) _, err = msgEthTx.VerifySig(chainID)
if err != nil { if err != nil {
return ctx, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "signature verification failed") return ctx, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, fmt.Sprintf("signature verification failed: %s", err.Error()))
} }
// NOTE: when signature verification succeeds, a non-empty signer address can be
// retrieved from the transaction on the next AnteDecorators.
return next(ctx, msgEthTx, simulate) return next(ctx, msgEthTx, simulate)
} }
@ -169,10 +172,10 @@ func (avd AccountVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, s
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type: %T", tx) return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type: %T", tx)
} }
// sender address should be in the tx cache // sender address should be in the tx cache from the previous AnteHandle call
address := msgEthTx.From() address := msgEthTx.From()
if address == nil { if address.Empty() {
panic("sender address is nil") panic("sender address cannot be empty")
} }
acc := avd.ak.GetAccount(ctx, address) acc := avd.ak.GetAccount(ctx, address)
@ -188,19 +191,20 @@ func (avd AccountVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, s
) )
} }
// validate sender has enough funds // validate sender has enough funds to pay for gas cost
balance := avd.bk.GetBalance(ctx, acc.GetAddress(), emint.DenomDefault) balance := avd.bk.GetBalance(ctx, acc.GetAddress(), emint.DenomDefault)
if balance.Amount.BigInt().Cmp(msgEthTx.Cost()) < 0 { if balance.Amount.BigInt().Cmp(msgEthTx.Cost()) < 0 {
return ctx, sdkerrors.Wrapf( return ctx, sdkerrors.Wrapf(
sdkerrors.ErrInsufficientFunds, sdkerrors.ErrInsufficientFunds,
"%s < %s%s", balance.String(), msgEthTx.Cost().String(), emint.DenomDefault, "sender balance < tx gas cost (%s < %s%s)", balance.String(), msgEthTx.Cost().String(), emint.DenomDefault,
) )
} }
return next(ctx, tx, simulate) return next(ctx, tx, simulate)
} }
// NonceVerificationDecorator that the nonce matches // NonceVerificationDecorator that the account nonce from the transaction matches
// the sender account sequence.
type NonceVerificationDecorator struct { type NonceVerificationDecorator struct {
ak auth.AccountKeeper ak auth.AccountKeeper
} }
@ -220,10 +224,10 @@ func (nvd NonceVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, sim
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type: %T", tx) return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type: %T", tx)
} }
// sender address should be in the tx cache // sender address should be in the tx cache from the previous AnteHandle call
address := msgEthTx.From() address := msgEthTx.From()
if address == nil { if address.Empty() {
panic("sender address is nil") panic("sender address cannot be empty")
} }
acc := nvd.ak.GetAccount(ctx, address) acc := nvd.ak.GetAccount(ctx, address)
@ -272,8 +276,8 @@ func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula
// sender address should be in the tx cache // sender address should be in the tx cache
address := msgEthTx.From() address := msgEthTx.From()
if address == nil { if address.Empty() {
panic("sender address is nil") panic("sender address cannot be empty")
} }
// Fetch sender account from signature // Fetch sender account from signature
@ -337,28 +341,33 @@ func NewIncrementSenderSequenceDecorator(ak auth.AccountKeeper) IncrementSenderS
// AnteHandle handles incrementing the sequence of the sender. // AnteHandle handles incrementing the sequence of the sender.
func (issd IncrementSenderSequenceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { func (issd IncrementSenderSequenceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
// no need to increment sequence on RecheckTx // get and set account must be called with an infinite gas meter in order to prevent
// additional gas from being deducted.
gasMeter := ctx.GasMeter()
ctx = ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
// no need to increment sequence on RecheckTx mode
if ctx.IsReCheckTx() && !simulate { if ctx.IsReCheckTx() && !simulate {
ctx = ctx.WithGasMeter(gasMeter)
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.
oldCtx := ctx.WithBlockGasMeter(sdk.NewInfiniteGasMeter())
msgEthTx, ok := tx.(evmtypes.MsgEthereumTx) msgEthTx, ok := tx.(evmtypes.MsgEthereumTx)
if !ok { if !ok {
ctx = ctx.WithGasMeter(gasMeter)
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type: %T", tx) return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type: %T", tx)
} }
// increment sequence of all signers // increment sequence of all signers
for _, addr := range msgEthTx.GetSigners() { for _, addr := range msgEthTx.GetSigners() {
acc := issd.ak.GetAccount(oldCtx, addr) acc := issd.ak.GetAccount(ctx, addr)
if err := acc.SetSequence(acc.GetSequence() + 1); err != nil { if err := acc.SetSequence(acc.GetSequence() + 1); err != nil {
panic(err) panic(err)
} }
issd.ak.SetAccount(oldCtx, acc) issd.ak.SetAccount(ctx, acc)
} }
// set the original gas meter
ctx = ctx.WithGasMeter(gasMeter)
return next(ctx, tx, simulate) return next(ctx, tx, simulate)
} }