When a block author constructs a block, it must limit the block's execution time. A block body consists of a series of extrinsics. To be economically sustainable and to limit spam, some transactions --- primarily those dispatched by users --- require a fee prior to transaction execution
inclusion_fee = base_fee + length_fee + [targeted_fee_adjustment * weight_fee]
final_fee = inclusion_fee + tip
base_feederived from the base weight covers inclusion overhead like signature verification.
base_fee= 1250000000000 (wei)
length_feeis set to length _fee per byte multiplied by the length of the encoded extrinsic. In which:
length_feeper byte= 10^12 (Dimension: wei/byte)
targeted_fee_adjustmentis a multiplier that can tune the final fee based on the congestion of the network. A targeted adjustment is implemented to define a target saturation level of block weight. If the previous block is more saturated, then the fees are slightly increased. Similarly, if the previous block has fewer transactions than the target, fees are decreased by a small amount.
weight_feeis calculated using two parameters:The
ExtrinsicBaseWeightthat is declared in the runtime and applies to all extrinsics.The
#[pallet::weight]annotation that accounts for an extrinsic's complexity.
weight_fee= 10^4 * weight tx (Dimension: wei)
Inclusion fees must be computable prior to execution, and therefore can only represent fixed logic. Some transactions uses other strategies to warrant limiting resources. For example,
Bonds: A bond is a type of fee that will either be returned or slashed after some on-chain event. For example, runtime developers may want to implement a bond in order to participate in a vote; in this example the bond could be returned at the end of the referendum or slashed if the voter tried anything malicious.
Deposits: Deposits are fees that may be returned later. For example, users may be required to pay a deposit in order to execute an operation that uses storage; if a subsequent operation frees that storage, the user's deposit could be returned.
Limits: Runtime developers are free to enforce constant or configurable limits on certain operations. For example, the default Staking pallet only allows nominators to nominate 16 validators in order to limit the complexity of the validator election process.
Note thatif you query the chain for a transaction fee, it will only return the inclusion fee.
A struct to update the weight multiplier per block. It implements `Convert<Multiplier, Multiplier>`, meaning that it can convert the previous multiplier to the next one. This should be called on
on_finalizeof a block, prior to potentially cleaning the weight data from the system module.
s = previous block weight
s'= ideal block weight
m = maximum block weight
diff = (s - s')/m v = 0.00001
t1 = (v * diff)
t2 = (v * diff)^2 / 2
next_multiplier = prev_multiplier * (1 + t1 + t2)
(s', v)must be given as the
Getimplementation of the
Tgeneric type. Moreover,
Mmust provide the minimum allowed value for the multiplier. Note that a runtime should ensure with tests that the combination of this
Vis not such that the multiplier can drop to zero and never recover.
s'is interpreted as a portion in the normal transaction capacity of the block. For example, given
s' == 0.25and
AvailableBlockRatio = 0.75, then the target fullness is 0.25 of the normal capacity and 0.1875 of the entire block.
This implementation implies the bound:
v ≤ p / k * (s − s')
- or, solving for
p >= v * k * (s - s')
pis the amount of change over
- in a fully congested chain:
p >= v * k * (1 - s').
- in an empty chain:
p >= v * k * (-s').
For example, when all blocks are full and there are 28800 blocks per day (default in
substrate-node) and v == 0.00001, s' == 0.1875, we'd have:
p >= 0.00001 * 28800 * 0.8125
p >= 0.234