Files
pezkuwi-subxt/substrate/frame/elections-phragmen
Peter Goodspeed-Niklaus 44d5aba80d Create a macro which automates creation of benchmark test suites. (#8104)
* Create a macro which automates creation of benchmark test suites.

* bump impl_version

* allow unused on test_bench_by_name

* use proper doctest ignore attribute

* Explicitly hand the Module to the test suite

Much better practice than depending on it showing up implicitly in
the namespace.

* explicitly import what we need into `mod tests`

* bench_module is `ident` not `tt`

Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com>

* allow end users to specify arguments for new_test_ext

This turned out to be surprisingly easy. On reflection, it turns out
that of course the compiler can't eagerly evaluate the function call,
but needs to paste it in everywhere desired.

* enable explicitly specifying the path to the benchmarks invocation

also enable optional trailing commas

* Revert "bump impl_version"

This reverts commit 0209e4de33fd43873f8cfc6875815d0fd6151e63.

* list failing benchmark tests and the errors which caused the failure

* harden benchmark tests against internal panics

* suppress warning about ignored profiles

unfortunately, setting the profile here doesn't do anything; we'd
need to set it in every leaf package anyway. However, as this was
just making the default explicit anyway, I think it's safe enough
to remove entirely.

* impl_benchmark_test_suite for assets

* impl_benchmark_test_suite for balances

* impl_benchmark_test_suite for bounties

* impl_benchmark_test_suite for Collective

* impl_benchmark_test_suite for Contracts

* impl_benchmark_test_suite for Democracy

* don't impl_benchmark_test_suite for Elections-Phragmen

* impl_benchmark_test_suite for Identity

Note that Identity tests currently fail. They failed in an identical
way before this change, so as far as I'm concerned, the status quo is
good enough for now.

* impl_benchmark_test_suite for ImOnline

* impl_benchmark_test_suite for indices

For this crate also, the test suite fails identically with and without
this change, so we can say that this change is not the cause of the
tests' failure to compile.

* impl_benchmark_test_suite for lottery

* impl_benchmark_test_suite for merkle-mountain-range

* impl_benchmark_test_suite for Multisig

These tests fail identically with and without the change, so the change
seems unlikely to be the origin of the failures.

* impl_benchmark_test_suite for offences

* impl_benchmark_test_suite for Proxy

Fails identically with and without this change.

* impl_benchmark_test_suite for scheduler

* impl_benchmark_test_suite for session

It turns out to be important to be able to exclude items marked
`#[extra]` sometimes. Who knew?

* impl_benchmark_test_suite for staking

* impl_benchmark_test_suite for system

* impl_benchmark_test_suite for timestamp

* impl_benchmark_test_suite for tips

* impl_benchmark_test_suite for treasury

* impl_benchmark_test_suite for utility

Note that benchmark tests fail identically before and after this change.

* impl_benchmark_test_suite for vesting

* fix wrong module name in impl_benchmark_test_suite in Offences

* address line length nits

* enable optional keyword argument: exec_name

Took a _lot_ of macro-wrangling to get the functionality that I want,
but now you have the option to pass in

```rust
impl_benchmark_test_suite!(
	Elections,
	crate::tests::ExtBuilder::default().desired_members(13).desired_runners_up(7),
	crate::tests::Test,
	exec_name = build_and_execute,
);
```

and have it expand out properly. A selected fragment of the expansion:

```rust
        fn test_benchmarks() {
            crate::tests::ExtBuilder::default()
                .desired_members(13)
                .desired_runners_up(7)
                .build_and_execute(|| {
```

* get rid of dead code

Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com>
2021-02-16 10:01:20 +01:00
..
2021-02-10 19:23:18 +01:00
2020-11-30 22:01:18 +00:00

Phragmén Election Module.

An election module based on sequential phragmen.

Term and Round

The election happens in rounds: every N blocks, all previous members are retired and a new set is elected (which may or may not have an intersection with the previous set). Each round lasts for some number of blocks defined by TermDuration storage item. The words term and round can be used interchangeably in this context.

TermDuration might change during a round. This can shorten or extend the length of the round. The next election round's block number is never stored but rather always checked on the fly. Based on the current block number and TermDuration, the condition BlockNumber % TermDuration == 0 being satisfied will always trigger a new election round.

Voting

Voters can vote for any set of the candidates by providing a list of account ids. Invalid votes (voting for non-candidates) are ignored during election. Yet, a voter might vote for a future candidate. Voters reserve a bond as they vote. Each vote defines a value. This amount is locked from the account of the voter and indicates the weight of the vote. Voters can update their votes at any time by calling vote() again. This keeps the bond untouched but can optionally change the locked value. After a round, votes are kept and might still be valid for further rounds. A voter is responsible for calling remove_voter once they are done to have their bond back and remove the lock.

Voters also report other voters as being defunct to earn their bond. A voter is defunct once all of the candidates that they have voted for are neither a valid candidate anymore nor a member. Upon reporting, if the target voter is actually defunct, the reporter will be rewarded by the voting bond of the target. The target will lose their bond and get removed. If the target is not defunct, the reporter is slashed and removed. To prevent being reported, voters should manually submit a remove_voter() as soon as they are in the defunct state.

Candidacy and Members

Candidates also reserve a bond as they submit candidacy. A candidate cannot take their candidacy back. A candidate can end up in one of the below situations:

  • Winner: A winner is kept as a member. They must still have a bond in reserve and they are automatically counted as a candidate for the next election.
  • Runner-up: Runners-up are the best candidates immediately after the winners. The number of runners_up to keep is configurable. Runners-up are used, in order that they are elected, as replacements when a candidate is kicked by [remove_member], or when an active member renounces their candidacy. Runners are automatically counted as a candidate for the next election.
  • Loser: Any of the candidate who are not a winner are left as losers. A loser might be an outgoing member or runner, meaning that they are an active member who failed to keep their spot. An outgoing will always lose their bond.
Renouncing candidacy.

All candidates, elected or not, can renounce their candidacy. A call to [Module::renounce_candidacy] will always cause the candidacy bond to be refunded.

Note that with the members being the default candidates for the next round and votes persisting in storage, the election system is entirely stable given no further input. This means that if the system has a particular set of candidates C and voters V that lead to a set of members M being elected, as long as V and C don't remove their candidacy and votes, M will keep being re-elected at the end of each round.

Module Information

License: Apache-2.0