Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Store voters in unsorted bags to get good stake iteration properties #9081

Closed
wants to merge 101 commits into from
Closed
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
101 commits
Select commit Hold shift + click to select a range
a549691
start sketching out how voter bags might be implemented
coriolinus Jun 11, 2021
bdfabd2
storage getters and setters for Bag, Node
coriolinus Jun 11, 2021
450c344
node getters and iterators for VoterList, Bag
coriolinus Jun 11, 2021
21e79ee
simplify get_npos_voters
coriolinus Jun 11, 2021
f4998e2
simplify fn voters
coriolinus Jun 11, 2021
8960daa
VoterList::insert
coriolinus Jun 11, 2021
f9d061d
VoterList::remove
coriolinus Jun 11, 2021
1e7dfd9
nodes are doubly-linked
coriolinus Jun 14, 2021
7f6460f
Merge remote-tracking branch 'origin/master' into prgn-nominator-unso…
coriolinus Jun 14, 2021
c6bcc76
impl fn update_position_for, update voter counts appropriately
coriolinus Jun 14, 2021
82154dd
keep VoterBagFor updated
coriolinus Jun 14, 2021
294cd99
manipulate VoterList everywhere which seems relevant
coriolinus Jun 15, 2021
9787daf
start sketching out `notional_bag_for`
coriolinus Jun 15, 2021
a857f59
`notional_bag_for` doesn't need a type parameter
coriolinus Jun 15, 2021
1a50bba
implement voter bag thresholds in terms of a precomputed list
coriolinus Jun 17, 2021
5858569
Merge remote-tracking branch 'origin/master' into prgn-nominator-unso…
coriolinus Jun 18, 2021
721c2cb
fix a failing test
coriolinus Jun 18, 2021
92220ec
fix the rest of the non-benchmark tests
coriolinus Jun 18, 2021
033d87f
revert an accidental change
coriolinus Jun 21, 2021
18c8eef
adapt tests from benchmarking.rs for easier debugging
coriolinus Jun 21, 2021
9bd6682
investigate a theory as to why the payout_stakers tests are failing
coriolinus Jun 21, 2021
7a74fcf
Revert "investigate a theory as to why the payout_stakers tests are f…
coriolinus Jun 21, 2021
e0ae1c0
find threshold more directly
coriolinus Jun 24, 2021
6699654
fix failing benchmark tests
coriolinus Jun 24, 2021
871b525
debug_assert that voter count is accurate
coriolinus Jun 24, 2021
f221404
add extrinsic to rebag a stash
coriolinus Jun 24, 2021
976c41b
WIP: rebag benchmark
coriolinus Jun 24, 2021
37e666a
WIP: rebag benchmark
coriolinus Jun 25, 2021
b75b55b
make rebag test into a test case for easier debugging
coriolinus Jun 25, 2021
1cb9e26
WIP: rebag benchmark
coriolinus Jun 25, 2021
c03d6ea
Merge remote-tracking branch 'origin/master' into prgn-nominator-unso…
coriolinus Jun 28, 2021
27cbb79
fix rebag benchmark
coriolinus Jun 28, 2021
247f2a1
Merge remote-tracking branch 'origin/master' into prgn-nominator-unso…
coriolinus Jun 28, 2021
b650861
reduce diff
coriolinus Jun 28, 2021
9b53d4c
re-benchmark to add rebag
coriolinus Jun 29, 2021
ab048c6
add VoterList::regenerate()
coriolinus Jun 29, 2021
5583ae4
add VoterList migration
coriolinus Jun 29, 2021
ae67ae7
add benchmark for regenerate
coriolinus Jun 30, 2021
efe15e2
remove redundant check
coriolinus Jun 30, 2021
fb5431e
debug assertions that `VoterList` and `CounterFor{Nominators,Validato…
coriolinus Jun 30, 2021
ee7959d
remove extra whitespace
coriolinus Jun 30, 2021
f58bb3a
only emit rebag event on success
coriolinus Jun 30, 2021
1cd8730
Merge branch 'prgn-nominator-unsorted-bags' of github.com:paritytech/…
coriolinus Jun 30, 2021
3c92eda
add doc explaining the term voter
coriolinus Jun 30, 2021
22bc615
revamp/simplify rebag test
coriolinus Jun 30, 2021
4092fa8
ensure genesis accounts are placed into the correct nodes/bags
coriolinus Jun 30, 2021
2182abe
bond_extra implicitly rebags
coriolinus Jun 30, 2021
472baa9
types at top; doc public type
coriolinus Jun 30, 2021
f1e7fe7
start sketching out adjustable thresholds
coriolinus Jun 29, 2021
16e4774
add integrity test for voter bag threshold requirements
coriolinus Jun 29, 2021
2a4ebf7
get rid of BagIdx
coriolinus Jun 30, 2021
cc6d0df
implement migration logic for when the threshold list changes
coriolinus Jul 1, 2021
88195fe
start sketching out threshold proc macros
coriolinus Jul 1, 2021
70848ea
further refine macro signatures
coriolinus Jul 1, 2021
b630321
WIP: implement make_ratio macro
coriolinus Jul 2, 2021
8ce3bc0
start rethinking the process of producing threshold lists
coriolinus Jul 2, 2021
202def0
write helper functions to emit voter bags module
coriolinus Jul 2, 2021
4da8204
WIP: demo generating voter bags for a realistic runtime
coriolinus Jul 2, 2021
498ab65
rm unnecessary arg_enum
coriolinus Jul 2, 2021
734ea86
fix voter bags math
coriolinus Jul 5, 2021
3cfa8cf
add computed voter bags thresholds to node
coriolinus Jul 5, 2021
a05df69
fixup some docs
coriolinus Jul 5, 2021
2838b83
iter from large bags to small, fulfuilling the contract
coriolinus Jul 5, 2021
3f17724
make tests compile
coriolinus Jul 5, 2021
b73fd7f
add VoterBagThresholds to some configs
coriolinus Jul 5, 2021
c719c5c
Merge remote-tracking branch 'origin/master' into prgn-nominator-unso…
coriolinus Jul 5, 2021
4861789
ensure that iteration covers all voters even with implied final bag
coriolinus Jul 6, 2021
59041b7
use sp_std::boxed::Box;
coriolinus Jul 6, 2021
646f708
Merge remote-tracking branch 'origin/master' into prgn-nominator-unso…
coriolinus Jul 6, 2021
f5c8a4d
fix unused import
coriolinus Jul 6, 2021
5e05e3f
add some more voter bags tests
coriolinus Jul 7, 2021
dbf3a84
file_header.txt
coriolinus Jul 7, 2021
873005e
Merge remote-tracking branch 'origin/master' into prgn-nominator-unso…
coriolinus Jul 7, 2021
d5e0c8d
integrity test to ensure min bag exceeds existential weight
coriolinus Jul 9, 2021
dbfb951
add more debug assertions about node list length
coriolinus Jul 9, 2021
06e69a8
rm unused imports
coriolinus Jul 9, 2021
df75e66
Merge branch 'master' of github.com:paritytech/substrate into prgn-no…
kianenigma Jul 9, 2021
6f15cc3
Kian enters
kianenigma Jul 10, 2021
1b545e4
Update frame/election-provider-support/src/onchain.rs
kianenigma Jul 12, 2021
e0a00fd
Suggestions for #9081 (Store voters in unsorted bags) (#9328)
emostov Jul 21, 2021
008cacf
Merge master pre-fmt
emostov Jul 21, 2021
48ccfc9
merge fallout
emostov Jul 22, 2021
225eb47
Merge origin master with new formatting
emostov Jul 22, 2021
acc9183
Merge remote-tracking branch 'origin' into prgn-nominator-unsorted-bags
emostov Jul 22, 2021
1c56016
Run cargo +nightly fmt
emostov Jul 22, 2021
1f02cb4
Fix a bunch of stuff, remove not needed runtime arg of make-bags
kianenigma Jul 22, 2021
2f83f16
add logs
kianenigma Jul 22, 2021
abb61c1
Merge branch 'master' of github.com:paritytech/substrate into prgn-no…
kianenigma Jul 22, 2021
0df47b0
Glue the new staking bags to the election snapshot (#9415)
kianenigma Jul 23, 2021
c1c4fcd
Merge remote-tracking branch 'origin' into prgn-nominator-unsorted-bags
emostov Jul 23, 2021
2c5a20c
Merge branch 'master' of https://github.com/paritytech/substrate into…
emostov Jul 27, 2021
8706404
Update node runtime with VoterSnapshotPerBlock
emostov Jul 27, 2021
98a4b1f
Merge remote-tracking branch 'origin' into prgn-nominator-unsorted-bags
emostov Jul 27, 2021
ced6077
Unit test for pallet-staking unsorted bags feature (targets #9081) (#…
emostov Jul 28, 2021
da4814c
Try prepare for master merge
emostov Jul 28, 2021
d20278a
Try merge origin master
emostov Jul 28, 2021
530e4d2
Reduce diff
emostov Jul 28, 2021
99bd08b
Try merge origin master
emostov Jul 30, 2021
df990d3
Add comment for test to add
emostov Aug 1, 2021
1632747
Add in code TODO for update_position efficiency updates
emostov Aug 1, 2021
dc3328e
Try merge origin master
emostov Aug 2, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 42 additions & 41 deletions frame/staking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,8 +276,9 @@ pub mod testing_utils;
#[cfg(any(feature = "runtime-benchmarks", test))]
pub mod benchmarking;

pub mod slashing;
pub mod inflation;
pub mod slashing;
pub mod voter_bags;
pub mod weights;

use sp_std::{
Expand Down Expand Up @@ -353,6 +354,9 @@ type NegativeImbalanceOf<T> = <<T as Config>::Currency as Currency<
<T as frame_system::Config>::AccountId,
>>::NegativeImbalance;

type AccountIdOf<T> = <T as frame_system::Config>::AccountId;
kianenigma marked this conversation as resolved.
Show resolved Hide resolved
type VotingDataOf<T> = (AccountIdOf<T>, VoteWeight, Vec<AccountIdOf<T>>);
emostov marked this conversation as resolved.
Show resolved Hide resolved

/// Information regarding the active era (era in used in session).
#[derive(Encode, Decode, RuntimeDebug)]
pub struct ActiveEraInfo {
Expand Down Expand Up @@ -994,6 +998,28 @@ decl_storage! {
///
/// This is set to v6.0.0 for new networks.
StorageVersion build(|_: &GenesisConfig<T>| Releases::V6_0_0): Releases;

// The next storage items collectively comprise the voter bags: a composite data structure
// designed to allow efficient iteration of the top N voters by stake, mostly. See
// `mod voter_bags` for details.

/// How many voters are registered.
VoterCount: u32;

/// Which bag currently contains a particular voter.
///
/// This may not be the appropriate bag for the voter's weight if they have been rewarded or
/// slashed.
VoterBagFor: map hasher(twox_64_concat) T::AccountId => voter_bags::BagIdx;

/// The head and tail of each bag of voters.
VoterBags: map hasher(twox_64_concat) voter_bags::BagIdx => Option<voter_bags::Bag<T>>;

/// The nodes comprising each bag.
VoterNodes: double_map
hasher(twox_64_concat) voter_bags::BagIdx,
hasher(twox_64_concat) T::AccountId =>
Option<voter_bags::Node<T>>;
}
add_extra_genesis {
config(stakers):
Expand Down Expand Up @@ -2495,37 +2521,20 @@ impl<T: Config> Module<T> {
/// auto-chilled.
emostov marked this conversation as resolved.
Show resolved Hide resolved
///
/// Note that this is VERY expensive. Use with care.
pub fn get_npos_voters() -> Vec<(T::AccountId, VoteWeight, Vec<T::AccountId>)> {
let weight_of = Self::slashable_balance_of_fn();
let mut all_voters = Vec::new();

for (validator, _) in <Validators<T>>::iter() {
// append self vote
let self_vote = (validator.clone(), weight_of(&validator), vec![validator.clone()]);
all_voters.push(self_vote);
}
pub fn get_npos_voters(
maybe_max_len: Option<usize>,
voter_count: usize,
) -> Vec<VotingDataOf<T>> {
let wanted_voters = maybe_max_len.unwrap_or(voter_count).min(voter_count);

let weight_of = Self::slashable_balance_of_fn();
// collect all slashing spans into a BTreeMap for further queries.
let slashing_spans = <SlashingSpans<T>>::iter().collect::<BTreeMap<_, _>>();
emostov marked this conversation as resolved.
Show resolved Hide resolved

for (nominator, nominations) in <Nominators<T>>::iter() {
let Nominations { submitted_in, mut targets, suppressed: _ } = nominations;

// Filter out nomination targets which were nominated before the most recent
// slashing span.
targets.retain(|stash| {
slashing_spans
.get(stash)
.map_or(true, |spans| submitted_in >= spans.last_nonzero_slash())
});

if !targets.is_empty() {
let vote_weight = weight_of(&nominator);
all_voters.push((nominator, vote_weight, targets))
}
}

all_voters
voter_bags::VoterList::<T>::iter()
.filter_map(|node| node.voting_data(&weight_of, &slashing_spans))
.take(wanted_voters)
.collect()
}

pub fn get_npos_targets() -> Vec<T::AccountId> {
Expand All @@ -2544,24 +2553,16 @@ impl<T: Config> frame_election_provider_support::ElectionDataProvider<T::Account
fn voters(
maybe_max_len: Option<usize>,
) -> data_provider::Result<(Vec<(T::AccountId, VoteWeight, Vec<T::AccountId>)>, Weight)> {
// NOTE: reading these counts already needs to iterate a lot of storage keys, but they get
// cached. This is okay for the case of `Ok(_)`, but bad for `Err(_)`, as the trait does not
// report weight in failures.
let nominator_count = <Nominators<T>>::iter().count();
let validator_count = <Validators<T>>::iter().count();
let voter_count = nominator_count.saturating_add(validator_count);

if maybe_max_len.map_or(false, |max_len| voter_count > max_len) {
return Err("Voter snapshot too big");
}
let voter_count = voter_bags::VoterList::<T>::decode_len().unwrap_or_default();

let slashing_span_count = <SlashingSpans<T>>::iter().count();
let weight = T::WeightInfo::get_npos_voters(
nominator_count as u32,
validator_count as u32,
// TODO: fix the weight calculation here
0 as u32,
voter_count as u32,
slashing_span_count as u32,
);
Ok((Self::get_npos_voters(), weight))
Ok((Self::get_npos_voters(maybe_max_len, voter_count), weight))
}

fn targets(maybe_max_len: Option<usize>) -> data_provider::Result<(Vec<T::AccountId>, Weight)> {
Expand Down
Loading