Question:
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)?
Answer:
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 u128
, the 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 pallet_staking::Pallet::get_npos_voters
).
Question:
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.
Answer:
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: ExtendedBalance
, a 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.