Minimum Fee setting (gaiad)

Hoping this can be a general thread on fees in the context of validator operations. To get things started:

Are there any good resources on the “minimum_fees” setting for gaiad? Specifically, I am trying to understand what it is intended to achieve.

Is it used solely as an anti-spam measure (CheckTx), thus preventing propagation via mempool of insufficiently funded transactions?

If above is correct, it seems like it would be appropriate to set this on sentry nodes, but could be left untouched on validators?

As operators will choose different values, it seems to me that only proposed TXs with fees >= highest value in +2/3 validator set will be included in blocks.

If that is correct, what happens with validators that set minimum_fees to high?

From a user perspective it is interesting to know if insufficiently funded TXs are censored immediately, or if they propagate and wait until a “cheap” proposer comes along.

I am wondering if minimum_fees shouldn’t be a global setting (genesis.json), ensuring that operators and users are not guessing at random what a sensible level would be?


Fee’s intended only as a anti-spam mechanism at the moment.

We don’t implement things like mempool or gossip prioritization based on fees.

The expectation is that most Cosmos chains will have so much capacity/throughput to make fees a small part of the early years of the system.

The current design prices transactions on the basis of min fee * gas to filter transactions out of the mem pool.

Currently the minimum units for the staking coins are not a great fit for a fine grained setting of these values. We could 1000 x the amount of photinos.

Stake will be able to be set in larger units when this is dealt with.

I am finding a disconnect between the minimum fee I set when starting gaiad and the fee that I am required to pay - there is always a 20STAKE difference. In the following scenario, I connect gaiacli directly to my validator which has been started with a 1STAKE minimum fee. On issuing a TX the required fee is 21STAKE. Similarly starting with a 1MSTAKE min fee results in a 1,000,020STAKE required fee.

$ gaiad start --minimum_fees=1STAKE
$ gaiacli tx dist withdraw-rewards --chain-id=genki-3001 --is-validator
ERROR: {"codespace":"sdk","code":14,"message":"insufficient fee, got: \"0\" required: \"21STAKE\""}
$ gaiad start --minimum_fees=1000000STAKE
$ gaiacli tx dist withdraw-rewards --chain-id=genki-3001 --is-validator
ERROR: {"codespace":"sdk","code":14,"message":"insufficient fee, got: \"0\" required: \"1000020STAKE\""}

Changing from STAKE to photinos also experiences a similar “offset” in required fees. Although the value of the offset is different for photinos.

Does anyone know where this “offset” is coming from? and how to remove it?

1 Like

The actual minimum fee is min fee * gas

A transaction that requires 5 signature verifications to verify should cost more than a transaction that requires 1 sig verification. sets the ratio of gas to fee units which are currently fixed.

It might be an improved design in the future to enable settings both the min fee units and the unit to gas ratio but it doesn’t make sense in the MVP system at all.

There is an adjusted value that you must meet defined here: So it depends on not only the fees you provide but also the gas you set, where the gasPerUnitCost is 10000.

I believe you can think of it in the following manner (correct me if I’m wrong here):

gasCost = (tx.gas / gasPerUnitCost)
adjFee = gasCost + minFee
assert(tx.Fee >= adjFee)

The above happens per denomination.

1 Like

To get a better understanding of how this works, it would be interesting to do a thought experiment.

Imagine 100 validators, where 99 have set minimum_fees=100STAKE and the remaining validator didn’t set any minimum fees.

If a client (invoker of BroadcastTx) sends a transaction with insufficient fees to either of the 99 validators, they will fail immediately on CheckTx(), which means the transaction doesn’t enter mempool and the client will be notified of the error.

This effectively censors the transaction, which I believe is as intended.

The client now learns that there is a validator that does not set minimum_fees. She deliver the TX to the validator, which accepts it into the mempool and gossips it to some of the 99 other validators. All of these will silently discard the TX, as it falls below minimum fees.

Effectively, this leaves the TX only with the “free” validator which might eventually propose a block which includes the transaction.

Now the question is: how does the 99 other validators receive the TX, so that they can apply it locally to the state machine? My understanding is the proposal includes TX hashes (not the actual TX data), so does this happen out-of-band to the normal gossip?


Please describe the way to remove the need for a fee on my transactions (when I propose the block), but still maintain the need for a fee for all other transactions. I believe there is a sentry architecture solution to this… also it would be useful to understand why it works.

what if below happens?

  1. tx with no fee broadcasted
  2. tx with 50STAKE fee broadcasted

if a validator proposed a block and the validator has 1stake minfee and the gas cost is 20stake.

Then the later tx is eligible to be included but not the former one.

Then the second tx bypass first tx and included in the block? or should wait until tx1 is included?

What if the generator of tx1 and tx2 is different?

How should be the result? based on the intention of sdk?

Im not sure I follow? The 1st tx wont pass CheckTx so it wont enter the mempool. When the validator receives the 2nd tx, it’ll pass CheckTx and be included in the block.

first tx is successfully broadcasted but not included in a block yet. a pending status

The 1st tx will be rejected by your proposer.

so basically proposer skips all the lackfee txs and include all enoghfee txs. therefore the order of txs doesnt matter. Thank you!

1 Like

The solution to this is to a minimum fee on set on your sentry nodes and no minimum fee on your validator node.

The only way to get a transaction to your validator node would be to submit a tx directly to the validator node via RPC.

The transactions would remain the validators mempool until time to propose.

We don’t do any sort of prioritization based on transaction fees