From da7eff8b25fb04aca4f39b38673a2493bc40ad56 Mon Sep 17 00:00:00 2001 From: yaruwangway <69694322+yaruwangway@users.noreply.github.com> Date: Tue, 31 Jan 2023 12:46:12 +0100 Subject: [PATCH] docs: bypass messages (#2091) * docs: bypass msg * docs: update globalfee docs * docs: formatting * Update globalfee.md * docs: fix link * docs: min_gas_prices -> minimum-gas-prices * docs: Updating globalfee docs (#2107) * add maxBypassMinFeeMsgGasUsage var and docstring * improve docstring in FeeDecorator.AnteHandle * updating docs * refactor globalfee documentation * refactor docs * fix typo * Update x/globalfee/ante/fee.go Co-authored-by: MSalopek <35486649+MSalopek@users.noreply.github.com> --------- Co-authored-by: Matija Salopek Co-authored-by: MSalopek <35486649+MSalopek@users.noreply.github.com> * docs: update globalfee doc * cleanup examples --------- Co-authored-by: Marius Poke Co-authored-by: Matija Salopek Co-authored-by: MSalopek <35486649+MSalopek@users.noreply.github.com> --- ante/ante.go | 9 +- docs/modules/globalfee.md | 260 ++++++++++++++++++++++---------------- x/globalfee/ante/fee.go | 30 +++-- 3 files changed, 182 insertions(+), 117 deletions(-) diff --git a/ante/ante.go b/ante/ante.go index 57c260201bcd8..f1e1ce391dabd 100644 --- a/ante/ante.go +++ b/ante/ante.go @@ -46,6 +46,12 @@ func NewAnteHandler(opts HandlerOptions) (sdk.AnteHandler, error) { sigGasConsumer = ante.DefaultSigVerificationGasConsumer } + // maxBypassMinFeeMsgGasUsage is the maximum gas usage per message + // so that a transaction that contains only message types that can + // bypass the minimum fee can be accepted with a zero fee. + // For details, see gaiafeeante.NewFeeDecorator() + var maxBypassMinFeeMsgGasUsage uint64 = 200_000 + anteDecorators := []sdk.AnteDecorator{ ante.NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first ante.NewRejectExtensionOptionsDecorator(), @@ -53,7 +59,8 @@ func NewAnteHandler(opts HandlerOptions) (sdk.AnteHandler, error) { ante.NewTxTimeoutHeightDecorator(), ante.NewValidateMemoDecorator(opts.AccountKeeper), ante.NewConsumeGasForTxSizeDecorator(opts.AccountKeeper), - gaiafeeante.NewFeeDecorator(opts.BypassMinFeeMsgTypes, opts.GlobalFeeSubspace, opts.StakingSubspace, 200_000), + gaiafeeante.NewFeeDecorator(opts.BypassMinFeeMsgTypes, opts.GlobalFeeSubspace, opts.StakingSubspace, maxBypassMinFeeMsgGasUsage), + ante.NewDeductFeeDecorator(opts.AccountKeeper, opts.BankKeeper, opts.FeegrantKeeper), ante.NewSetPubKeyDecorator(opts.AccountKeeper), // SetPubKeyDecorator must be called before all signature verification decorators ante.NewValidateSigCountDecorator(opts.AccountKeeper), diff --git a/docs/modules/globalfee.md b/docs/modules/globalfee.md index a4d2a863720ed..b8853c0b96b09 100644 --- a/docs/modules/globalfee.md +++ b/docs/modules/globalfee.md @@ -1,33 +1,90 @@ -# Gaia Fees and Fees Check +# Gaia Fees and Fees Checks -## Gaia Fees +## Fee Parameters +The CosmosHub allows managing fees using 3 parameters: -The CosmosHub has two types of fees, both of which, are the [sdk.DecCoins](https://github.com/cosmos/cosmos-sdk/blob/a1143138716b64bc4fa0aa53c0f0fa59eb675bb7/types/dec_coin.go#L158) type: +1. setting global fees (`MinimumGasPricesParam`) +Global fees are defined at the network level by setting `MinimumGasPricesParam`, via [Gov Proposals](https://hub.cosmos.network/main/governance/proposals/) -- global fees (are defined at the network level, via [Gov Proposals](https://hub.cosmos.network/main/governance/proposals/)) -- min_gas_prices (are specified validator node, in the `config/app.toml` configuration file) - -### Global Fees +2. `minimum-gas-prices` +This parameter is part of the node configuration, it can be set in the `config/app.toml` configuration file. + +3. `bypass-min-fee-msg-types` +This parameter is part of the node configuration, it can be set in the `config/app.toml` configuration file. +This represents a list of message types that will be excluded from paying any fees for inclusion in a block. + +Both global fees (`MinimumGasPricesParam`) and `minimum-gas-prices` represent a list of coins, each denoted by an amount and domination as defined by [sdk.DecCoins](https://github.com/cosmos/cosmos-sdk/blob/82ce891aa67f635f3b324b7a52386d5405c5abd0/types/dec_coin.go#L158) + + +## Concepts -#### Global Fees Concept +## Global Fees -Global fees are the fees that each transaction incurs—except [bypass fee message types](###Bypass Fees Message Types). Global fees are set up through a governance proposal which must be voted on by validators. +Global fees consist of a list of `sdk.DecCoins` e.g., `[1uatom, 2stake]`. +Every transaction must pay per unit of gas **at least** one of the amounts stated in this list in the corresponding denomination (denom). By this notion, global fees allow a network to impose a minimum transaction fee. -For [global fees](https://github.com/cosmos/gaia/blob/82c4353ab1b04cf656a8c95d226c30c7845f157b/x/globalfee/types/params.go#L54-L99) to be valid: +The paid fees must be paid in at least one denom from the global fees list and the corresponding amount per unit of gas must be greater than or equal to the corresponding amount in the global fees list. -- fees have to be alphabetically sorted by denomination (denom) +A global fees list must meet the following properties: +- fees have to be alphabetically sorted by denom; - fees must have non-negative amount, with a valid and unique denom (i.e. no duplicate denoms are allowed). -Global fees allow denoms with zero coins or value. -Zero value coins are used to define fee denoms, when the chain does not charge fees. Each transaction (except bypass transactions) have to meet the following global fee requirements: +There are **two exceptions** from the global fees rules that allow zero fee transactions: + +1. Transactions that contain only [message types that can bypass the minimum fee](#bypass-fees-message-types) may have zero fees. We refer to this as _bypass transactions_. Node operators can choose to define these message types (for each node) via the `bypass-fee-message-types` configuration parameter. + +2. One of the entries in the global fees list has a zero amount, e.g., `0uatom`, and the corresponding denom, e.g., `uatom`, is not present in `minimum-gas-prices`. + +Additionally, node operators may set additional minimum gas prices which can be larger than the _global_ minimum gas prices defined on chain. + -- All denoms of the paid fees (except zero coins) have to be a subset of the global fee's denom set. -- All paidfees' contain at least one denom that is present and greater than/or equal to the amount of the same denom in globalfee. +### minimum-gas-prices -#### Query Global Fees +The `minimum-gas-prices` config parameter allows node operators to impose additional requirements for minimum fees. The following rules apply: -CLI queries to retrieve the global fee value: +- The denoms in `min-gas-prices` that are not present in the global fees list are ignored. +- The amounts in `min-gas-prices` are considered only if they are greater than the amounts for the corresponding denoms in the global fees list. + +## Bypass Fees Message Types + +Bypass messages are messages that are exempt from paying fees. The above global fees and `minimum-gas-prices` checks do not apply for transactions that satisfy the following conditions: + +- Contains only bypass message types, i.e., bypass transactions. +- The total gas used is less than or equal to `len(messages) * MaxBypassMinFeeMsgGasUsage`. Note: the current `MaxBypassMinFeeMsgGasUsage` is set to `200,000`. +- In case of non-zero transaction fees, the denom has to be a subset of denoms defined in the global fees list. + +Node operators can configure `bypass-min-fee-msg-types` in `config/app.toml`. + +Nodes created using Gaiad `v7.0.2` or later use `["/ibc.core.channel.v1.MsgRecvPacket", "/ibc.core.channel.v1.MsgAcknowledgement","/ibc.applications.transfer.v1.MsgTransfer"]` as defaults. Nodes with `bypass-min-fee-msg-types = []` or missing this field in `app.toml` also use default bypass message types. + +Nodes created using Gaiad `v7.0.1` or earlier do not have `bypass-min-fee-msg-types` configured in `config/app.toml` - they are also using default values. The `bypass-min-fee-msg-types` config option can be added to `config/app.toml` before the `[telemetry]` field. + +An example of `bypass-min-fee-msg-types` in `app.toml`: + +```shell + +############################################################################### +### Custom Gaia Configuration ### +############################################################################### +# bypass-min-fee-msg-types defines custom message types the operator may set that +# will bypass minimum fee checks during CheckTx. +# +# Example: +# ["/ibc.core.channel.v1.MsgRecvPacket", "/ibc.core.channel.v1.MsgAcknowledgement", ...] +bypass-min-fee-msg-types = ["/ibc.core.channel.v1.MsgRecvPacket", "/ibc.core.channel.v1.MsgAcknowledgement","/ibc.applications.transfer.v1.MsgTransfer"] +``` + + +## Fee AnteHandler Behaviour + +The denoms in the global fees list and the `minimum-gas-prices` param are merged and de-duplicated while keeping the higher amounts. Denoms that are only in the `minimum-gas-prices` param are discarded. + +If the denoms of the transaction fees are a subset of the merged fees and at least one of the amounts of the transaction fees is greater than or equal to the corresponding required fees amount, the transaction can pass the fee check, otherwise an error will occur. + +## Queries + +CLI queries can be used to retrieve the global fee value: ```shell gaiad q globalfee minimum-gas-prices @@ -35,11 +92,9 @@ gaiad q globalfee minimum-gas-prices gaiad q params subspace globalfee MinimumGasPricesParam ``` -#### Empty Global Fees and Default Global Fees +If the global fee is not set, the query returns an empty global fees list: `minimum_gas_prices: []`. In this case the Cosmos Hub will use `0uatom` as global fee in this case (the default fee denom). -When the global fee is not setup, the query will return an empty globalfee list: `minimum_gas_prices: []`. Gaiad will use `0uatom` as global fee in this case. This is due to the CosmosHub accepting uatom as fee denom by default. - -#### Setting Up Global Fees via Gov Proposals +## Setting Up Global Fees via Gov Proposals An example of setting up a global fee by a gov proposals is shown below. @@ -49,7 +104,7 @@ gov submit-proposal param-change proposal.json A `proposal.json` example: -``` +```json { "title": "Global fees Param Change", "description": "Update global fees", @@ -64,111 +119,104 @@ A `proposal.json` example: } ``` -Please note: in the above "value" field, coins must sorted alphabetically by denom. +**Note:** in the above "value" field, coins must sorted alphabetically by denom. -### Min_gas_prices -min_gas_prices are a node's further requirement of fees. Zero coins are removed from min_gas_prices when [parsing min_gas_prices](https://github.com/cosmos/cosmos-sdk/blob/3a097012b59413641ac92f18f226c5d6b674ae42/baseapp/options.go#L27), this is different from global fees. +## Examples -- If the min_gas_prices set a denom that is not global fees's denom set. This min_gas_prices denom will not be considered when paying fees. -- If the min_gas_prices have a denom in global fees's denom set, and the min_gas_prices are lower than global fees, the fee still need to meet the global fees. -- If the min_gas_prices have a denom in global fees's denom set, and the min_gas_prices are higher than global fees, the fee need to meet the min_gas_prices. +Here are a few examples to clarify the relationship between global fees, minimum-gas-prices and transaction fees. -## Fee Checks +**Note:** Transactions can include zero-coin fees. However, these fees are removed from the transaction fees during the fee [parsing](https://github.com/cosmos/cosmos-sdk/blob/e716e4103e934344aa7be6dc9b5c453bdec5f225/client/tx/factory.go#L144) / [santitizing](https://github.com/cosmos/cosmos-sdk/blob/e716e4103e934344aa7be6dc9b5c453bdec5f225/types/dec_coin.go#L172) before reaching the fee AnteHandler. +This means `paidfee = "1uatom, 0stake"` and `paidfee = "1uatom"` are equivalent, and similarly, `paidfee = "0uatom"` is equivalent to `paidfee = ""`. +In the following examples, zero-coin fees are removed from the transaction fees. -Global fees, min_gas_prices and the paid fees all allow zero coins setup. After parsing the fee coins, zero coins and paid fees will be removed from the min_gas_prices and paid fees. +### Case 1 -Only global fees might contain zero coins, which is used to define the allowed denoms of paid fees. +**Setting:** globalfee=[], minimum-gas-prices=0.1uatom, gas=2000000. -The [Fee AnteHandle](../../x/globalfee/ante/fee.go) will take global fees and min_gas_prices and merge them into one [combined `sdk.Deccoins`](https://github.com/cosmos/gaia/blob/f2be720353a969b6362feff369218eb9056a60b9/ante/fee.go#L79) according to the denoms and amounts of global fees and min_gas_prices. +Note that this is the same case as globalfee=0uatom, minimum-gas-prices=0.1uatom, gas=2000000. -If the paid fee is a subset of the combined fees set and the paid fee amount is greater than or equal to the required fees amount, the transaction can pass the fee check, otherwise an error will occur. + - paidfee = "2000000 * 0.1uatom", `pass` + - paidfee = "2000000 * 0.1uatom, 1stake", `fail` (unexpected denom) + - paidfee = "", `fail` (insufficient funds) -### Bypass Fees Message Types +### Case 2 -The above global fee and min_as_prices fee checks do not apply to bypass message types. Transactions of bypass message types are free of fee charge. However, if the bypass type transactions still carry nonzero fees, the denom has to be a subset of denoms that global fees defined. +**Setting:** globalfee=[], minimum-gas-prices="", gas=2000000. -A node can set up its own bypass message types by modify the configuration parameter `bypass-min-fee-msg-types` in `config/app.toml` file. Nodes using `app.toml` files initialized by gaiad version of v7.0.1 or earlier might not have `bypass-min-fee-msg-types`, users can insert it before the field `[telemetry]` in `app.toml`. +Note that this is the same case as globalfee=0uatom, minimum-gas-prices="", gas=2000000. -An example: + - paidfee = "", `pass` + - paidfee = "2000000 * 0.1uatom", `pass` + - paidfee = "2000000 * 0.1stake", `fail` (unexpected denom) + +### Case 3 -```shell +**Setting:** globalfee=[0.2uatom], minimum-gas-prices=0.1uatom, gas=2000000 (global fee is higher than min_as_price). -############################################################################### -### Custom Gaia Configuration ### -############################################################################### -# bypass-min-fee-msg-types defines custom message types the operator may set that -# will bypass minimum fee checks during CheckTx. -# -# Example: -# ["/ibc.core.channel.v1.MsgRecvPacket", "/ibc.core.channel.v1.MsgAcknowledgement", ...] -bypass-min-fee-msg-types = ["/ibc.core.channel.v1.MsgRecvPacket", "/ibc.core.channel.v1.MsgAcknowledgement","/ibc.applications.transfer.v1.MsgTransfer"] -``` +Note that this is the same case as globalfee=0.2uatom, minimum-gas-prices="", gas=2000000. + + - paidfee = "2000000 * 0.2uatom", `pass` + - paidfee = "2000000 * 0.1uatom", `fail` (insufficient funds) + - paidfee = "2000000 * 0.2uatom, 1stake", `fail` (unexpected denom) + - paidfee = "2000000 * 0.2stake", `fail` (unexpected denom) + - paidfee = "", `fail` (insufficient funds) + +### Case 4 -Even though each node can set its own `min_gas_prices` and `bypass-min-fee-msg-types`, when the transactions enters a validator's mempool, the transactions carried fees have to satisfy the validator's `min_gas_prices` and `bypass-min-fee-msg-types`'s requirement in order for the validators to process the transactions. +**Setting:** globalfee=[0.1uatom], minimum-gas-prices=0.2uatom, gas=2000000 (global fee is lower than min_as_price). -## Examples +Note that the required amount in globalfee is overwritten by the amount in minimum-gas-prices. -Here are a few examples to clarify the relationship between global fees, min_gas_prices and paid fees. + - paidfee = "2000000 * 0.2uatom", `pass` + - paidfee = "2000000 * 0.1uatom", `fail` (insufficient funds) + - paidfee = "2000000 * 0.2uatom, 1stake", `fail` (unexpected denom) + - paidfee = "2000000 * 0.2stake", `fail` (unexpected denom) + - paidfee = "", `fail` (insufficient funds) + - paidfee = 0uatom, `fail` (insufficient funds) + +### Case 5 -- **Case 1**: globalfee=[], min_gas_prices=0.0001uatom, gas=2000000 +**Setting:** globalfee=[0uatom, 1stake], minimum-gas-prices="", gas=200000. - This is the same case as globalfee=0uatom, min_gas_prices=0.0001uatom, gas=2000000. - - paidfee = "2000000 * 0.0001uatom", pass - - paidfee = "2000000 * 0.0001uatom, 0stake", pass - - paidfee = "2000000 * 0.0001uatom, 1stake", fail - - paidfee = "2000000 * 0.0001/2uatom", fail - - paidfee = "", pass + - paidfee ="2000000 * 0.5stake", `fail` (insufficient funds) + - paidfee ="", `pass` + - paidfee ="2000000 * 1uatom, 0.5stake", `pass` + - paidfee ="2000000 * 1stake", `pass` -- **Case 2**: globalfee=[], min_gas_prices="", gas=2000000 - - paidfee = "", pass - - paidfee = "0uatom", pass - - paidfee = "1uatom", pass - - paidfee = "0uatom, 0stake", pass - - paidfee = "0uatom, 1stake", fail - -- **Case 3**: globalfee=0.0002uatom, min_gas_prices=0.0001uatom, gas=2000000 (global fee is lower than min_as_price) - - paidfee = "2000000 * 0.0002uatom", pass - - paidfee = "2000000 * 0.0001uatom", fail - - paidfee = "2000000 * 0.0002uatom, 1stake", fail - - paidfee = "2000000 * 0.0002uatom, 0stake", pass - - paidfee = "2000000 * 0.0002stake", fail - - paidfee = "", fail - - paidfee = 0uatom, fail - -- **Case 4**: globalfee=0.0001uatom, min_gas_prices=0.0002uatom, gas=2000000 (global fee is higher than min_as_price) - - paidfee = "2000000 * 0.0002uatom", pass - - paidfee = "2000000 * 0.0001uatom", fail - - paidfee = "2000000 * 0.0002uatom, 1stake", fail - - paidfee = "2000000 * 0.0002uatom, 0stake", pass - - paidfee = "2000000 * 0.0002stake", fail - - paidfee = "", fail - - paidfee = 0uatom, fail - -- **Case 5**: globalfee=[0uatom, 1stake], min_gas_prices="", gas=200000. -- fees="2000000 *0uatom, 2000000* 0.5stake", fail, (this is due to [fee parsing, zero coins are removed](https://github.com/cosmos/cosmos-sdk/blob/e716e4103e934344aa7be6dc9b5c453bdec5f225/client/tx/factory.go#L144), it equals to paidfees = 0.5stake in this case) -- paidfees="", pass -- paidfees="2000000 * 1uatom, 0.5stake", pass -- paidfees="0uatom, 0stake" pass, (due to the parsing of paidfees, it makes paidfees="") -- paidfees="2000000 * 1stake", pass - -- **Case 6**: globalfee=[0.001uatom, 1stake], min_gas_prices=0.002uatom, gas=200000. - - paidfee = "2000000 * 0.0002uatom", pass - - paidfee = "2000000 * 0.0001uatom", fail - - paidfee = "2000000 * 1stake", pass - - paidfee = "2000000 * 1/2stake", fail - - paidfee = "2000000 *0.0001uatom, 2000000*1stake", pass - - paidfee = "2000000 *0.0002atom, 2000000*1/2stake", pass - - paidfee = "2000000 *0.0001uatom, 2000000*1/2stake", fail +### Case 6 + +**Setting:** globalfee=[0.1uatom, 1stake], minimum-gas-prices=0.2uatom, gas=200000. + +Note that the required amount of `uatom` in globalfee is overwritten by the amount in minimum-gas-prices. + + - paidfee = "2000000 * 0.2uatom", `pass` + - paidfee = "2000000 * 0.1uatom", `fail` (insufficient funds) + - paidfee = "2000000 * 1stake", `pass` + - paidfee = "2000000 * 0.5stake", `fail` (insufficient funds) + - paidfee = "2000000 * 0.1uatom, 2000000 * 1stake", `pass` + - paidfee = "2000000 * 0.2atom, 2000000 * 0.5stake", `pass` + - paidfee = "2000000 * 0.1uatom, 2000000 * 0.5stake", `fail` (insufficient funds) -- **Case 7**:globalfee=[0.0001uatom], min_gas_prices=0.0002uatom,1stake, gas=200000. +### Case 7 + +**Setting:** globalfee=[0.1uatom], minimum-gas-prices=0.2uatom,1stake, gas=200000, bypass-min-fee-msg-types = ["/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward"] + +Note that the required amount of `uatom` in globalfee is overwritten by the amount in minimum-gas-prices. +Also, the `1stake` in minimum-gas-prices is ignored. + + - msg withdraw-all-rewards with paidfee="", `pass` + - msg withdraw-all-rewards with paidfee="200000 * 0.05uatom", `pass` + - msg withdraw-all-rewards with paidfee="200000 * 1stake", `fail` (unexpected denom) + +### Case 8 + +**Setting:** globalfee=[1uatom], minimum-gas-prices="", gas=300000, bypass-min-fee-msg-types = ["/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward"] - `bypass-min-fee-msg-types = ["/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward"]` - - msg withdraw-all-rewards with paidfee=0uatom, pass - - msg withdraw-all-rewards with paidfee=200000 * 0.0001/2uatom, pass - - msg withdraw-all-rewards with paidfee=0stake,0photon, pass - - msg withdraw-all-rewards with paidfee=200000 * 1stake, 0photon, fail + - msg withdraw-all-rewards with paidfee="", `fail` (gas limit exceeded for bypass transactions) + - msg withdraw-all-rewards with paidfee="300000 * 0.5uatom", `fail` (gas limit exceeded for bypass transactions, insufficient funds) + - msg withdraw-all-rewards with paidfee="300000 * 1uatom", `pass` -## Reference +## References -- [Fee caculations: fee and gas](https://docs.cosmos.network/main/basics/gas-fees.html) +- [Gas and Fees in Cosmos SDK](https://docs.cosmos.network/main/basics/gas-fees.html) diff --git a/x/globalfee/ante/fee.go b/x/globalfee/ante/fee.go index 7e5fe188949d2..650acb2f77997 100644 --- a/x/globalfee/ante/fee.go +++ b/x/globalfee/ante/fee.go @@ -59,10 +59,12 @@ func (mfd FeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, ne gas := feeTx.GetGas() msgs := feeTx.GetMsgs() - // Only check for minimum fees and global fee if the execution mode is CheckTx and the tx does - // not contain operator configured bypass messages. If the tx does contain - // operator configured bypass messages only, it's total gas must be less than - // or equal to a constant, otherwise minimum fees and global fees are checked to prevent spam. + // Accept zero fee transactions only if both of the following statements are true: + // - the tx contains only message types that can bypass the minimum fee, + // see BypassMinFeeMsgTypes; + // - the total gas limit per message does not exceed MaxBypassMinFeeMsgGasUsage, + // i.e., totalGas <= len(msgs) * MaxBypassMinFeeMsgGasUsage + // Otherwise, minimum fees and global fees are checked to prevent spam. containsOnlyBypassMinFeeMsgs := mfd.bypassMinFeeMsgs(msgs) doesNotExceedMaxGasUsage := gas <= uint64(len(msgs))*mfd.MaxBypassMinFeeMsgGasUsage allowedToBypassMinFee := containsOnlyBypassMinFeeMsgs && doesNotExceedMaxGasUsage @@ -74,30 +76,38 @@ func (mfd FeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, ne } requiredFees := getMinGasPrice(ctx, feeTx) + // Only check for minimum fees and global fee if the execution mode is CheckTx if !ctx.IsCheckTx() || simulate { return next(ctx, tx, simulate) } if !allowedToBypassMinFee { + // Either the transaction contains at least on message of a type + // that cannot bypass the minimum fee or the total gas limit exceeds + // the imposed threshold. As a result, check that the fees are in + // expected denominations and the amounts are greater or equal than + // the expected amounts. allFees = CombinedFeeRequirement(requiredGlobalFees, requiredFees) - // this is to ban 1stake passing if the globalfee is 1photon or 0photon - // if feeCoins=[] and requiredGlobalFees has 0denom coins then it should pass. + // Check that the fees are in expected denominations. Note that a zero fee + // is accepted if the global fee has an entry with a zero amount, e.g., 0uatoms. if !DenomsSubsetOfIncludingZero(feeCoins, allFees) { return ctx, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "fee is not a subset of required fees; got %s, required: %s", feeCoins, allFees) } - // At least one feeCoin amount must be GTE to one of the requiredGlobalFees + // Check that the amounts of the fees are greater or equal than + // the expected amounts, i.e., at least one feeCoin amount must + // be greater or equal to one of the combined required fees. if !IsAnyGTEIncludingZero(feeCoins, allFees) { return ctx, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "insufficient fees; got: %s required: %s", feeCoins, allFees) } } else { - // bypass tx without pay fee + // Transactions with zero fees are accepted if len(feeCoins) == 0 { return next(ctx, tx, simulate) } - // when the tx is bypass msg type, still need to check the denom is not some unknown denom - // bypass with fee, fee denom must in requiredGlobalFees + // If the transaction fee is non-zero, then check that the fees are in + // expected denominations. if !DenomsSubsetOfIncludingZero(feeCoins, requiredGlobalFees) { return ctx, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "fees denom is wrong; got: %s required: %s", feeCoins, requiredGlobalFees) }