mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-07-03 21:37:23 +00:00
Moving NposSolution to frame (#11031)
* Move `sp-npos-elections-solution-type` to `frame-election-provider-support` First stab at it, will need to amend some more stuff * Fixing tests * Fixing tests * Fixing cargo.toml for std configuration * fmt * Committing suggested changes renaming, and re exporting macro. * Removing unneeded imports * Move `NposSolution` to frame * Removing `npos_election` dependencies Implementing _fpes better * some feedback for moving NPoSSolution to frame * fmt * more formatting * Fixed some imports and fmt * Fixing docs Co-authored-by: kianenigma <kian@parity.io>
This commit is contained in:
@@ -167,17 +167,86 @@
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
pub mod onchain;
|
||||
use frame_support::{traits::Get, BoundedVec};
|
||||
pub mod traits;
|
||||
use codec::{Decode, Encode};
|
||||
use frame_support::{traits::Get, BoundedVec, RuntimeDebug};
|
||||
use sp_runtime::traits::Bounded;
|
||||
use sp_std::{fmt::Debug, prelude::*};
|
||||
|
||||
/// Re-export some type as they are used in the interface.
|
||||
/// Re-export the solution generation macro.
|
||||
pub use frame_election_provider_solution_type::generate_solution_type;
|
||||
/// Re-export some type as they are used in the interface.
|
||||
pub use sp_arithmetic::PerThing;
|
||||
pub use sp_npos_elections::{
|
||||
Assignment, ElectionResult, ExtendedBalance, IdentifierT, PerThing128, Support, Supports,
|
||||
VoteWeight,
|
||||
Assignment, ElectionResult, Error, ExtendedBalance, IdentifierT, PerThing128, Support,
|
||||
Supports, VoteWeight,
|
||||
};
|
||||
pub use traits::NposSolution;
|
||||
|
||||
// re-export for the solution macro, with the dependencies of the macro.
|
||||
#[doc(hidden)]
|
||||
pub use codec;
|
||||
#[doc(hidden)]
|
||||
pub use scale_info;
|
||||
#[doc(hidden)]
|
||||
pub use sp_arithmetic;
|
||||
#[doc(hidden)]
|
||||
pub use sp_std;
|
||||
// Simple Extension trait to easily convert `None` from index closures to `Err`.
|
||||
//
|
||||
// This is only generated and re-exported for the solution code to use.
|
||||
#[doc(hidden)]
|
||||
pub trait __OrInvalidIndex<T> {
|
||||
fn or_invalid_index(self) -> Result<T, Error>;
|
||||
}
|
||||
|
||||
impl<T> __OrInvalidIndex<T> for Option<T> {
|
||||
fn or_invalid_index(self) -> Result<T, Error> {
|
||||
self.ok_or(Error::SolutionInvalidIndex)
|
||||
}
|
||||
}
|
||||
|
||||
/// The [`IndexAssignment`] type is an intermediate between the assignments list
|
||||
/// ([`&[Assignment<T>]`][Assignment]) and `SolutionOf<T>`.
|
||||
///
|
||||
/// The voter and target identifiers have already been replaced with appropriate indices,
|
||||
/// making it fast to repeatedly encode into a `SolutionOf<T>`. This property turns out
|
||||
/// to be important when trimming for solution length.
|
||||
#[derive(RuntimeDebug, Clone, Default)]
|
||||
#[cfg_attr(feature = "std", derive(PartialEq, Eq, Encode, Decode))]
|
||||
pub struct IndexAssignment<VoterIndex, TargetIndex, P: PerThing> {
|
||||
/// Index of the voter among the voters list.
|
||||
pub who: VoterIndex,
|
||||
/// The distribution of the voter's stake among winning targets.
|
||||
///
|
||||
/// Targets are identified by their index in the canonical list.
|
||||
pub distribution: Vec<(TargetIndex, P)>,
|
||||
}
|
||||
|
||||
impl<VoterIndex, TargetIndex, P: PerThing> IndexAssignment<VoterIndex, TargetIndex, P> {
|
||||
pub fn new<AccountId: IdentifierT>(
|
||||
assignment: &Assignment<AccountId, P>,
|
||||
voter_index: impl Fn(&AccountId) -> Option<VoterIndex>,
|
||||
target_index: impl Fn(&AccountId) -> Option<TargetIndex>,
|
||||
) -> Result<Self, Error> {
|
||||
Ok(Self {
|
||||
who: voter_index(&assignment.who).or_invalid_index()?,
|
||||
distribution: assignment
|
||||
.distribution
|
||||
.iter()
|
||||
.map(|(target, proportion)| Some((target_index(target)?, proportion.clone())))
|
||||
.collect::<Option<Vec<_>>>()
|
||||
.or_invalid_index()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// A type alias for [`IndexAssignment`] made from [`NposSolution`].
|
||||
pub type IndexAssignmentOf<C> = IndexAssignment<
|
||||
<C as NposSolution>::VoterIndex,
|
||||
<C as NposSolution>::TargetIndex,
|
||||
<C as NposSolution>::Accuracy,
|
||||
>;
|
||||
|
||||
/// Types that are used by the data provider trait.
|
||||
pub mod data_provider {
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Traits for the election operations.
|
||||
|
||||
use crate::{Assignment, IdentifierT, IndexAssignmentOf, PerThing128, VoteWeight};
|
||||
use codec::Encode;
|
||||
use scale_info::TypeInfo;
|
||||
use sp_arithmetic::traits::{Bounded, UniqueSaturatedInto};
|
||||
use sp_npos_elections::{ElectionScore, Error, EvaluateSupport};
|
||||
use sp_std::{
|
||||
convert::{TryFrom, TryInto},
|
||||
fmt::Debug,
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
/// An opaque index-based, NPoS solution type.
|
||||
pub trait NposSolution
|
||||
where
|
||||
Self: Sized + for<'a> sp_std::convert::TryFrom<&'a [IndexAssignmentOf<Self>], Error = Error>,
|
||||
{
|
||||
/// The maximum number of votes that are allowed.
|
||||
const LIMIT: usize;
|
||||
|
||||
/// The voter type. Needs to be an index (convert to usize).
|
||||
type VoterIndex: UniqueSaturatedInto<usize>
|
||||
+ TryInto<usize>
|
||||
+ TryFrom<usize>
|
||||
+ Debug
|
||||
+ Copy
|
||||
+ Clone
|
||||
+ Bounded
|
||||
+ Encode
|
||||
+ TypeInfo;
|
||||
|
||||
/// The target type. Needs to be an index (convert to usize).
|
||||
type TargetIndex: UniqueSaturatedInto<usize>
|
||||
+ TryInto<usize>
|
||||
+ TryFrom<usize>
|
||||
+ Debug
|
||||
+ Copy
|
||||
+ Clone
|
||||
+ Bounded
|
||||
+ Encode
|
||||
+ TypeInfo;
|
||||
|
||||
/// The weight/accuracy type of each vote.
|
||||
type Accuracy: PerThing128;
|
||||
|
||||
/// Get the length of all the voters that this type is encoding.
|
||||
///
|
||||
/// This is basically the same as the number of assignments, or number of active voters.
|
||||
fn voter_count(&self) -> usize;
|
||||
|
||||
/// Get the total count of edges.
|
||||
///
|
||||
/// This is effectively in the range of {[`Self::voter_count`], [`Self::voter_count`] *
|
||||
/// [`Self::LIMIT`]}.
|
||||
fn edge_count(&self) -> usize;
|
||||
|
||||
/// Get the number of unique targets in the whole struct.
|
||||
///
|
||||
/// Once presented with a list of winners, this set and the set of winners must be
|
||||
/// equal.
|
||||
fn unique_targets(&self) -> Vec<Self::TargetIndex>;
|
||||
|
||||
/// Get the average edge count.
|
||||
fn average_edge_count(&self) -> usize {
|
||||
self.edge_count().checked_div(self.voter_count()).unwrap_or(0)
|
||||
}
|
||||
|
||||
/// Compute the score of this solution type.
|
||||
fn score<A, FS>(
|
||||
self,
|
||||
stake_of: FS,
|
||||
voter_at: impl Fn(Self::VoterIndex) -> Option<A>,
|
||||
target_at: impl Fn(Self::TargetIndex) -> Option<A>,
|
||||
) -> Result<ElectionScore, Error>
|
||||
where
|
||||
for<'r> FS: Fn(&'r A) -> VoteWeight,
|
||||
A: IdentifierT,
|
||||
{
|
||||
let ratio = self.into_assignment(voter_at, target_at)?;
|
||||
let staked =
|
||||
sp_npos_elections::helpers::assignment_ratio_to_staked_normalized(ratio, stake_of)?;
|
||||
let supports = sp_npos_elections::to_supports(&staked);
|
||||
Ok(supports.evaluate())
|
||||
}
|
||||
|
||||
/// Remove a certain voter.
|
||||
///
|
||||
/// This will only search until the first instance of `to_remove`, and return true. If
|
||||
/// no instance is found (no-op), then it returns false.
|
||||
///
|
||||
/// In other words, if this return true, exactly **one** element must have been removed self.
|
||||
fn remove_voter(&mut self, to_remove: Self::VoterIndex) -> bool;
|
||||
|
||||
/// Build self from a list of assignments.
|
||||
fn from_assignment<FV, FT, A>(
|
||||
assignments: &[Assignment<A, Self::Accuracy>],
|
||||
voter_index: FV,
|
||||
target_index: FT,
|
||||
) -> Result<Self, Error>
|
||||
where
|
||||
A: IdentifierT,
|
||||
for<'r> FV: Fn(&'r A) -> Option<Self::VoterIndex>,
|
||||
for<'r> FT: Fn(&'r A) -> Option<Self::TargetIndex>;
|
||||
|
||||
/// Convert self into a `Vec<Assignment<A, Self::Accuracy>>`
|
||||
fn into_assignment<A: IdentifierT>(
|
||||
self,
|
||||
voter_at: impl Fn(Self::VoterIndex) -> Option<A>,
|
||||
target_at: impl Fn(Self::TargetIndex) -> Option<A>,
|
||||
) -> Result<Vec<Assignment<A, Self::Accuracy>>, Error>;
|
||||
}
|
||||
Reference in New Issue
Block a user