github.com/cosmos/cosmos-sdk@v0.50.10/x/auth/ante/validator_tx_fee.go (about)

     1  package ante
     2  
     3  import (
     4  	"math"
     5  
     6  	errorsmod "cosmossdk.io/errors"
     7  	sdkmath "cosmossdk.io/math"
     8  
     9  	sdk "github.com/cosmos/cosmos-sdk/types"
    10  	sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
    11  )
    12  
    13  // checkTxFeeWithValidatorMinGasPrices implements the default fee logic, where the minimum price per
    14  // unit of gas is fixed and set by each validator, can the tx priority is computed from the gas price.
    15  func checkTxFeeWithValidatorMinGasPrices(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, int64, error) {
    16  	feeTx, ok := tx.(sdk.FeeTx)
    17  	if !ok {
    18  		return nil, 0, errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx")
    19  	}
    20  
    21  	feeCoins := feeTx.GetFee()
    22  	gas := feeTx.GetGas()
    23  
    24  	// Ensure that the provided fees meet a minimum threshold for the validator,
    25  	// if this is a CheckTx. This is only for local mempool purposes, and thus
    26  	// is only ran on check tx.
    27  	if ctx.IsCheckTx() {
    28  		minGasPrices := ctx.MinGasPrices()
    29  		if !minGasPrices.IsZero() {
    30  			requiredFees := make(sdk.Coins, len(minGasPrices))
    31  
    32  			// Determine the required fees by multiplying each required minimum gas
    33  			// price by the gas limit, where fee = ceil(minGasPrice * gasLimit).
    34  			glDec := sdkmath.LegacyNewDec(int64(gas))
    35  			for i, gp := range minGasPrices {
    36  				fee := gp.Amount.Mul(glDec)
    37  				requiredFees[i] = sdk.NewCoin(gp.Denom, fee.Ceil().RoundInt())
    38  			}
    39  
    40  			if !feeCoins.IsAnyGTE(requiredFees) {
    41  				return nil, 0, errorsmod.Wrapf(sdkerrors.ErrInsufficientFee, "insufficient fees; got: %s required: %s", feeCoins, requiredFees)
    42  			}
    43  		}
    44  	}
    45  
    46  	priority := getTxPriority(feeCoins, int64(gas))
    47  	return feeCoins, priority, nil
    48  }
    49  
    50  // getTxPriority returns a naive tx priority based on the amount of the smallest denomination of the gas price
    51  // provided in a transaction.
    52  // NOTE: This implementation should be used with a great consideration as it opens potential attack vectors
    53  // where txs with multiple coins could not be prioritize as expected.
    54  func getTxPriority(fee sdk.Coins, gas int64) int64 {
    55  	var priority int64
    56  	for _, c := range fee {
    57  		p := int64(math.MaxInt64)
    58  		gasPrice := c.Amount.QuoRaw(gas)
    59  		if gasPrice.IsInt64() {
    60  			p = gasPrice.Int64()
    61  		}
    62  		if priority == 0 || p < priority {
    63  			priority = p
    64  		}
    65  	}
    66  
    67  	return priority
    68  }