Feeless Chain

Current Fee Implementation

In the current implementation, which can be referred to as “semi-feeless”, transaction fees are dynamically adjusted based on network congestion. Under normal conditions, transactions are feeless, but when the network becomes congested, the fee system is triggered and will increase as long as the blockchain stays saturated. This system is implemented directly at the step where the transaction weights are converted into fees. Additionally, allowing data to be stored on-chain (such as with remarks) could lead to a vulnerability by increasing the chain size with abuse of microtransactions, which could become problematic in the long term, even if fees are applied.

Totally feeless

In Substrate, each transaction should be associated with a weight (then translated into a fee) proportional to the computation performed by the chain to prevent abuse. However, some operations do not incur fees and do not impact the chain. For example, calling an extrinsic with a non-existent account (e.g., zero balance, wrong key, etc.) will result in an error that could not incur a fee as the account has no balance. In these cases, the checks are performed by an extrinsic extension polkadot-sdk/substrate/frame/system/src/extensions/check_nonce.rs at master · paritytech/polkadot-sdk · GitHub. If the operations performed are small (meaning only one database read and minimal calculation), this approach ensures security.

I created a minimal proof of concept for a feeless chain: GitHub - bgallois/substrate-feeless-solochain-template. Each account is assigned a transaction rate that is checked and updated using an extrinsic extension. The chain remains secure from spamming by limiting each account to the specified rate of transactions (e.g., x transactions over y blocks). Since all information is stored in the AccountData, additional data can be stored at minimal cost; this will allow for features such as adding a quota for bytes stored per account, as well as modulating the rate and quota depending on whether the account is a member or not, among other possibilities.

The transaction extension system is currently undergoing refactoring (see Follow up work on `TransactionExtension` - fix weights and clean up `UncheckedExtrinsic` by georgepisaltu · Pull Request #6418 · paritytech/polkadot-sdk · GitHub), so we should only implement it once the new implementation is part of a release. However, it’s a good idea to start thinking about this approach, as it could be a valuable solution for our chain.

This is by no means a fully thought-through solution, and it can also be applied in conjunction with the current system, or vice versa, by monitoring the transaction rate/data stored in chain and limiting only users who are abusing the system.

This breaks the paradigm a little bit, so to summarize:

Current Semi-Feeless Feeless
Fee Forecast Depending on the network (0 or variable amount depending on the number of blocks where the network was saturated) Always 0
Transactions Rate Illimited Limited
Blockchain Size Increase Controlled by max allowed by block Controlled by block size and by account
Paradigm Rich accounts can prioritize transactions Everyone is equal
Incentive Fees go to treasury and can be spent for… No fee = no treasury
2 Likes

I don’t understand how it prevents someone to spam using one transaction per account, on millions of accounts.

Is the check computed offchain or in the runtime? If it’s in the runtime, the account must be slashed. If it’s offchain, we rely on the validators to enforce it.

Relying on the validators is acceptable for us since we have a closed smith set, but we still have to think how bad things can be if some validators are evil and how to respond to an attack.

1 Like

For non-legitimate extrinsics, the protection is the same as if someone were creating millions of accounts with a zero balance and spamming a Polkadot node. The node checks if the account is sufficient, and nobody pays for that. In our case, the check to determine if the transaction rate is exceeded will have a similar complexity.

For legitimate transactions, the transaction rate should be set in accordance with the existential deposit to ensure that someone with substantial funds cannot create enough accounts to overload the chain.

It is also possible to implement a penalty system within the extension for accounts spamming the node.

1 Like

The extrinsic extension allows to determine whether a tx should be included or not. If some kind of rate is applied, it should include a minimum delay between account creation (by sending currency on it) and first tx inclusion. Otherwise this attack scenario would be quite harmful:

  • 1 000 000 ĞD on an account A
  • a batch extrinsic to send 1 ĞD on 1 000 000 accounts (included because falls within the allowed tx rate)
  • these 1 000 000 accounts sending 1 ĞD to 1 000 000 other accounts
  • these 1 000 000 accounts sending 1 ĞD to 1 000 000 other accounts
  • (repeat)

The repeat rate of this operation would be guided by the “first tx delay”.

(I moved this topic to R&D which suits more for the moment).

For chains with the utility pallet, in the case of a batch extrinsic (where the extension is checked only once for many transactions), it will count as one within the rate limit. Therefore, either the utility pallet should be restricted to a certain number of calls per batch, or an additional extension/modification should be used to keep the rate in sync. In any case, a chain implementing a rate limit is unlikely to use the utility pallet with its default settings and open to any origin.

The batch case can also be addressed by enforcing a rate limit on the extrinsic size. Normally, the size of the batch transaction will be the sum of the sizes of each individual transaction, ensuring the count remains accurate.

In terms of account creation, the limitation will more likely be enforced by setting an existential deposit high enough to prevent even the richest users from creating a number of accounts that could pose a danger to the chain. This would address both batch scenarios and slow attacks.