Follow up of https://github.com/paritytech/substrate/pull/1978#issuecomment-472327208 https://github.com/paritytech/substrate/pull/1815#discussion_r265284213 https://github.com/paritytech/substrate/pull/1924#issuecomment-472415736
It is clear to me that my understanding of fees model is different to the one @gavofyork has in mind.
I would like to have this clearly documented to make sure everyone including future developers understands the fee model of substrate.
The questions are:
TransactionPayment and the purpose of it.TransactionPayment.base fee + tx size * byte fee + transfer/creation feebase fee + tx size * byte fee + gas feeTo my understanding, the purpose of transaction fee is to ensure the sender pays for at least of cost for the network to process this transaction. It also acts as a security gateway to ensure the cost to spam the network is high.
Therefore, the transaction fee should be direct proportion to the resources (CPU, storage, network) required to process this transaction. As a result, in addition to the mandatory fee base fee + tx size * byte fee that charged by executive module, each other runtime call should have additional fee that reflects on the complexity of the call. For example, create a new account with balances.transfer requires additional storage usage, and hence a higher account creation fee.
Without this feature, attacker could identify an expensive runtime call and use it to attack the network efficiently. Unless, of cause, all the runtime calls are simple and have O(1) computation complexity and storage usage, which I don't think will be the case for most of the parachains.
In my design, the fees module should achieve those goals:
fees.Charged event. A single event will be emitted for each transaction and clients (apps) can easily query this information.Currency or TransferAsset trait to modify the balance and charge fee, ChargeFee trait offers a unified way to charge fee. Fees module implementation will handle all the balance checking, liquidity checking, and accumulate the total fee.OnFeeCharged trait #1924 Next steps:
I can see those options to proceed forward:
ChargeFee trait and use it instead of the srml-fees moduleWhat is TransactionPayment and the purpose of it.
It is strictly the minimal payment required for the inclusion of the transaction on-chain to be valid, i.e. to not panic. Once the transaction is included on-chain it must be dispatched.
Some dispatch functions use insignificant amounts of resources beyond those already accounted for by the transaction payment. In such cases, no additional economic protections would be needed (e.g. by a withdrawal from the transaction-signer's account).
For other dispatch functions, the resource consumption may be significant or potentially significant based on parameters or state. In these instances additional economic protections are necessary to ensure the chain cannot be attacked through multiple resource-consumption transactions. It is up to the dispatch function in question to ensure that its logic is economically sound. This may be done through an initial additional withdrawal, a returnable-deposit (perhaps through reserve), an identity check (e.g. to ensure that they are a council member or validator), or some other means of restricting the scope for resource-draining. None of these additional economic protections are considered Transaction Payment, in Substrate's strict usage of the term.
What is transaction fee and the relationship between transaction fee and
TransactionPayment
"transaction fee" is not a formal term. Different people may mean different things by it in different contexts.
In very simple contexts where there are existing fixed-function blockchains such as Ethereum and Bitcoin, "transaction fee" is easily defined to mean "everything withdrawn from accounts controlled by the transaction author that is paid to the miner".
In Substrate, which is not a fixed-function state-transition, there is no such equivalent unless the chain expressly elects to make it so. In short, chains are free to decide their own meaning of the term, but Substrate itself does not imply anything.
The main reason behind this is flexibility. Substrate is not designed to provide fees to the block author and in some consensus methods, there may not even be a singular identifiable "block author". Some chains may choose to burn fees, others may pass them to one or more entities involved in block authorship, others (like Polkadot) may do a combination. Some more complex modules in Substrate may reserve "fees" and return them (or not) in the same block or some number of blocks later. None of this fits trivially and absolutely into a traditional definition of "transaction fees".
create a in memory temporary store for fees calculation to avoid the trie db overhead
This could work if placed in the executive module and if knowledge of the accumulated fees need not be exposed while executing extrinsics.
update existing fees module to avoid storage usage. Ensure the abstraction allows developer have those additional logic implemented in their own runtime.
This seems the most reasonable way forward. I'm happy to introduce a zero-cost abstraction that doesn't alter existing logic but that does facilitate better third-party usage.
Thanks for the clarification @gavofyork! Please make sure those definitions are listed in the substrate documentations site because they are very useful.
create a in memory temporary store for fees calculation to avoid the trie db overhead
This could work if placed in the
executivemodule _and_ if knowledge of the accumulated fees need not be exposed while executing extrinsics.
I no sure how to implement this so I will leave this for others.
update existing fees module to avoid storage usage. Ensure the abstraction allows developer have those additional logic implemented in their own runtime.
This seems the most reasonable way forward. I'm happy to introduce a zero-cost abstraction that doesn't alter existing logic but that does facilitate better third-party usage.
Cool. I will make a PR for this.