-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #202 from stratosnet/qb1582_gas-prices_flag_suppor…
…t_all_denoms Fix/QB-1582: Gwei/Stos denom not working with gas-price flag
- Loading branch information
Showing
3 changed files
with
166 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
package ante | ||
|
||
import ( | ||
"fmt" | ||
|
||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" | ||
"github.com/cosmos/cosmos-sdk/x/auth/types" | ||
) | ||
|
||
// MempoolFeeDecorator will check if the transaction's fee is at least as large | ||
// as the local validator's minimum gasFee (defined in validator config). | ||
// If fee is too low, decorator returns error and tx is rejected from mempool. | ||
// Note this only applies when ctx.CheckTx = true | ||
// If fee is high enough or not CheckTx, then call next AnteHandler | ||
// CONTRACT: Tx must implement FeeTx to use MempoolFeeDecorator | ||
type MempoolFeeDecorator struct{} | ||
|
||
func NewMempoolFeeDecorator() MempoolFeeDecorator { | ||
return MempoolFeeDecorator{} | ||
} | ||
|
||
func (mfd MempoolFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { | ||
feeTx, ok := tx.(sdk.FeeTx) | ||
if !ok { | ||
return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx") | ||
} | ||
|
||
feeCoins, err := sdk.ParseCoinsNormalized(feeTx.GetFee().String()) | ||
if err != nil { | ||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "fee parsing error: %s", feeCoins) | ||
} | ||
gas := feeTx.GetGas() | ||
|
||
// Ensure that the provided fees meet a minimum threshold for the validator, | ||
// if this is a CheckTx. This is only for local mempool purposes, and thus | ||
// is only ran on check tx. | ||
if ctx.IsCheckTx() && !simulate { | ||
minGasPrices := ctx.MinGasPrices() | ||
if !minGasPrices.IsZero() { | ||
requiredFees := make(sdk.Coins, len(minGasPrices)) | ||
|
||
// Determine the required fees by multiplying each required minimum gas | ||
// price by the gas limit, where fee = ceil(minGasPrice * gasLimit). | ||
glDec := sdk.NewDec(int64(gas)) | ||
for i, gp := range minGasPrices { | ||
fee := gp.Amount.Mul(glDec) | ||
requiredFees[i] = sdk.NewCoin(gp.Denom, fee.Ceil().RoundInt()) | ||
} | ||
|
||
if !feeCoins.IsAnyGTE(requiredFees) { | ||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "insufficient fees; got: %s required: %s", feeCoins, requiredFees) | ||
} | ||
} | ||
} | ||
|
||
return next(ctx, tx, simulate) | ||
} | ||
|
||
// DeductFeeDecorator deducts fees from the first signer of the tx | ||
// If the first signer does not have the funds to pay for the fees, return with InsufficientFunds error | ||
// Call next AnteHandler if fees successfully deducted | ||
// CONTRACT: Tx must implement FeeTx interface to use DeductFeeDecorator | ||
type DeductFeeDecorator struct { | ||
ak AccountKeeper | ||
bankKeeper types.BankKeeper | ||
feegrantKeeper FeegrantKeeper | ||
} | ||
|
||
func NewDeductFeeDecorator(ak AccountKeeper, bk types.BankKeeper, fk FeegrantKeeper) DeductFeeDecorator { | ||
return DeductFeeDecorator{ | ||
ak: ak, | ||
bankKeeper: bk, | ||
feegrantKeeper: fk, | ||
} | ||
} | ||
|
||
func (dfd DeductFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { | ||
feeTx, ok := tx.(sdk.FeeTx) | ||
if !ok { | ||
return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx") | ||
} | ||
|
||
if addr := dfd.ak.GetModuleAddress(types.FeeCollectorName); addr == nil { | ||
return ctx, fmt.Errorf("fee collector module account (%s) has not been set", types.FeeCollectorName) | ||
} | ||
|
||
fee, err := sdk.ParseCoinsNormalized(feeTx.GetFee().String()) | ||
if err != nil { | ||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "fee parsing error: %s", fee) | ||
} | ||
feePayer := feeTx.FeePayer() | ||
feeGranter := feeTx.FeeGranter() | ||
|
||
deductFeesFrom := feePayer | ||
|
||
// if feegranter set deduct fee from feegranter account. | ||
// this works with only when feegrant enabled. | ||
if feeGranter != nil { | ||
if dfd.feegrantKeeper == nil { | ||
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "fee grants are not enabled") | ||
} else if !feeGranter.Equals(feePayer) { | ||
err := dfd.feegrantKeeper.UseGrantedFees(ctx, feeGranter, feePayer, fee, tx.GetMsgs()) | ||
if err != nil { | ||
return ctx, sdkerrors.Wrapf(err, "%s not allowed to pay fees from %s", feeGranter, feePayer) | ||
} | ||
} | ||
|
||
deductFeesFrom = feeGranter | ||
} | ||
|
||
deductFeesFromAcc := dfd.ak.GetAccount(ctx, deductFeesFrom) | ||
if deductFeesFromAcc == nil { | ||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "fee payer address: %s does not exist", deductFeesFrom) | ||
} | ||
|
||
// deduct the fees | ||
if !fee.IsZero() { | ||
err = DeductFees(dfd.bankKeeper, ctx, deductFeesFromAcc, fee) | ||
if err != nil { | ||
return ctx, err | ||
} | ||
} | ||
|
||
events := sdk.Events{ | ||
sdk.NewEvent( | ||
sdk.EventTypeTx, | ||
sdk.NewAttribute(sdk.AttributeKeyFee, fee.String()), | ||
sdk.NewAttribute(sdk.AttributeKeyFeePayer, deductFeesFrom.String()), | ||
), | ||
} | ||
ctx.EventManager().EmitEvents(events) | ||
|
||
return next(ctx, tx, simulate) | ||
} | ||
|
||
// DeductFees deducts fees from the given account. | ||
func DeductFees(bankKeeper types.BankKeeper, ctx sdk.Context, acc types.AccountI, fees sdk.Coins) error { | ||
if !fees.IsValid() { | ||
return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "invalid fee amount: %s", fees) | ||
} | ||
|
||
err := bankKeeper.SendCoinsFromAccountToModule(ctx, acc.GetAddress(), types.FeeCollectorName, fees) | ||
if err != nil { | ||
return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, err.Error()) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters