Skip to content

Commit

Permalink
docs: bypass messages (cosmos#2091)
Browse files Browse the repository at this point in the history
* 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 (cosmos#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 <matija.salopek994@gmail.com>
Co-authored-by: MSalopek <35486649+MSalopek@users.noreply.github.com>

* docs: update globalfee doc

* cleanup examples

---------

Co-authored-by: Marius Poke <marius.poke@posteo.de>
Co-authored-by: Matija Salopek <matija.salopek994@gmail.com>
Co-authored-by: MSalopek <35486649+MSalopek@users.noreply.github.com>
  • Loading branch information
4 people authored Jan 31, 2023
1 parent ce1e96e commit da7eff8
Show file tree
Hide file tree
Showing 3 changed files with 182 additions and 117 deletions.
9 changes: 8 additions & 1 deletion ante/ante.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,21 @@ 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(),
ante.NewValidateBasicDecorator(),
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),
Expand Down
260 changes: 154 additions & 106 deletions docs/modules/globalfee.md
Original file line number Diff line number Diff line change
@@ -1,45 +1,100 @@
# 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
# or
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.

Expand All @@ -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",
Expand All @@ -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)
Loading

0 comments on commit da7eff8

Please sign in to comment.