In the docs for CurrencyToVote it says
the total issuance being passed in implies that the implementation must be aware of the fact that its values can affect the outcome. This implies that if the vote value is dependent on the total issuance, it should never be written to storage for later re-use.
And in U128CurrencyToVote (used by Polkadot), balances get divided by how many times the total issuance fits into a u64.
But the BagsList pallet stores these weights here and uses them for ordering. Does this mean that every time the total issuance hits a multiple of u64::MAX, new updates in the list are wildly out of sync with previous inserts (with those previous inserts having a much larger weight)?
Short answer: yes.
When using the bags list as the
SortedListProvider for pallet staking, once the total issuance increases over a multiple of
u64::MAX, new inserts will be out of sync. In this case rebag should be called on all the nodes already in the list. The rebag extrinsic is permissionless and thus the network can (and is incentivized to) "organically" self adjust.
If one had a chain where they expected the total issuance would cross
u64::MAX multiples frequently, this probably would be a suboptimal design choice.
So to remedy the aforementioned issue the bags list could be made more extensible by having a configurable
Weight type (probably something that impls
PartialOrd). For example if
Balance was a
Weight for the bags list could be set to a
u128 and then the
VoteWeightProvider could be defined to simply return the bonded balance of the account. (PRs welcome!) As far as I know, in the staking use case, the bags list itself doesn't need to use a
u64 for ordering weight (someone please correct me if I am wrong). The actual vote weight is calculated on the spot when collecting the voters (see
It also feels a little silly to use a u64 type for vote weights when the total_issuance in pallet-balances already has to fit into a Balance type which is a u128 for most chains.
Looking at the
pallet_staking::Config::CurrencyToVote docs we see:
Convert a balance into a number used for election calculation. This must fit into a u64 but is allowed to be sensibly lossy. The u64 is used to communicate with the frame_election_provider_support crate which accepts u64 numbers and does operations in 128.
This is hinting that the election algorithmns need a type which can be extended to avoid overflowing arithmetic. And it does have one:
u128. Tangential, in theory one could use a
u128 for vote weight and a
u256 for the arithmetic, but a
u256 is not supported in rust and presumably other impls would have some negative performance consequences.