Crate tp_election_providers[][src]

Primitive traits for providing election functionality.

This crate provides two traits that could interact to enable extensible election functionality within FRAME pallets.

Something that will provide the functionality of election will implement ElectionProvider, whilst needing an associated ElectionProvider::DataProvider, which needs to be fulfilled by an entity implementing ElectionDataProvider. Most often, the data provider is the receiver of the election, resulting in a diagram as below:

                                        ElectionDataProvider
                         <------------------------------------------+
                         |                                          |
                         v                                          |
                   +-----+----+                              +------+---+
                   |          |                              |          |
pallet-do-election |          |                              |          | pallet-needs-election
                   |          |                              |          |
                   |          |                              |          |
                   +-----+----+                              +------+---+
                         |                                          ^
                         |                                          |
                         +------------------------------------------+
                                        ElectionProvider

It could also be possible that a third party pallet (C), provides the data of election to an election provider (B), which then passes the election result to another pallet (A).

Election Types

Typically, two types of elections exist:

  1. Stateless: Election data is provided, and the election result is immediately ready.
  2. Stateful: Election data is is queried ahead of time, and the election result might be ready some number of blocks in the future.

To accommodate both type of elections in one trait, the traits lean toward stateful election, as it is more general than the stateless. This is why ElectionProvider::elect has no parameters. All value and type parameter must be provided by the ElectionDataProvider trait, even if the election happens immediately.

Election Data

The data associated with an election, essentially what the ElectionDataProvider must convey is as follows:

  1. A list of voters, with their stake.
  2. A list of targets (i.e. candidates).
  3. A number of desired targets to be elected (i.e. winners)

In addition to that, the ElectionDataProvider must also hint ElectionProvider at when the next election might happen (ElectionDataProvider::next_election_prediction). A stateless election provider would probably ignore this. A stateful election provider can use this to prepare the election result in advance.

Nonetheless, an ElectionProvider shan’t rely on this and should preferably provide some means of fallback election as well, in case the elect was called immaturely early.

Example


type AccountId = u64;
type Balance = u64;
type BlockNumber = u32;

mod data_provider {
    use super::*;

    pub trait Config: Sized {
        type ElectionProvider: ElectionProvider<
            AccountId,
            BlockNumber,
            DataProvider = Module<Self>,
        >;
    }

    pub struct Module<T: Config>(std::marker::PhantomData<T>);

    impl<T: Config> ElectionDataProvider<AccountId, BlockNumber> for Module<T> {
        fn desired_targets() -> u32 {
            1
        }
        fn voters() -> Vec<(AccountId, VoteWeight, Vec<AccountId>)> {
            Default::default()
        }
        fn targets() -> Vec<AccountId> {
            vec![10, 20, 30]
        }
        fn next_election_prediction(now: BlockNumber) -> BlockNumber {
            0
        }
    }
}


mod generic_election_provider {
    use super::*;

    pub struct GenericElectionProvider<T: Config>(std::marker::PhantomData<T>);

    pub trait Config {
        type DataProvider: ElectionDataProvider<AccountId, BlockNumber>;
    }

    impl<T: Config> ElectionProvider<AccountId, BlockNumber> for GenericElectionProvider<T> {
        type Error = ();
        type DataProvider = T::DataProvider;

        fn elect() -> Result<Supports<AccountId>, Self::Error> {
            Self::DataProvider::targets()
                .first()
                .map(|winner| vec![(*winner, Support::default())])
                .ok_or(())
        }
    }
}

mod runtime {
    use super::generic_election_provider;
    use super::data_provider;
    use super::AccountId;

    struct Runtime;
    impl generic_election_provider::Config for Runtime {
        type DataProvider = data_provider::Module<Runtime>;
    }

    impl data_provider::Config for Runtime {
        type ElectionProvider = generic_election_provider::GenericElectionProvider<Runtime>;
    }

}

Modules

onchain

An implementation of ElectionProvider that does an on-chain sequential phragmen.

Structs

Assignment

A voter’s stake assignment among a set of targets, represented as ratios.

Traits

ElectionDataProvider

Something that can provide the data to an ElectionProvider.

ElectionProvider

Something that can compute the result of an election and pass it back to the caller.

PerThing

Re-export some type as they are used in the interface.

PerThing128

Aggregator trait for a PerThing that can be multiplied by u128 (ExtendedBalance).

Type Definitions

ExtendedBalance

A type in which performing operations on vote weights are safe.

Supports

A target-major representation of the the election outcome.

VoteWeight

A type which is used in the API of this crate as a numeric weight of a vote, most often the stake of the voter. It is always converted to ExtendedBalance for computation.