referrerpolicy=no-referrer-when-downgrade

sp_npos_elections/
helpers.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! Helper methods for npos-elections.
19
20use crate::{
21	Assignment, Error, ExtendedBalance, IdentifierT, PerThing128, StakedAssignment, Supports,
22	VoteWeight,
23};
24use alloc::{collections::BTreeMap, vec::Vec};
25use sp_arithmetic::PerThing;
26
27/// Converts a vector of ratio assignments into ones with absolute budget value.
28///
29/// Note that this will NOT attempt at normalizing the result.
30pub fn assignment_ratio_to_staked<A: IdentifierT, P: PerThing128, FS>(
31	ratios: Vec<Assignment<A, P>>,
32	stake_of: FS,
33) -> Vec<StakedAssignment<A>>
34where
35	for<'r> FS: Fn(&'r A) -> VoteWeight,
36{
37	ratios
38		.into_iter()
39		.map(|a| {
40			let stake = stake_of(&a.who);
41			a.into_staked(stake.into())
42		})
43		.collect()
44}
45
46/// Same as [`assignment_ratio_to_staked`] and try and do normalization.
47pub fn assignment_ratio_to_staked_normalized<A: IdentifierT, P: PerThing128, FS>(
48	ratio: Vec<Assignment<A, P>>,
49	stake_of: FS,
50) -> Result<Vec<StakedAssignment<A>>, Error>
51where
52	for<'r> FS: Fn(&'r A) -> VoteWeight,
53{
54	let mut staked = assignment_ratio_to_staked(ratio, &stake_of);
55	staked.iter_mut().try_for_each(|a| {
56		a.try_normalize(stake_of(&a.who).into()).map_err(|_| Error::ArithmeticError)
57	})?;
58	Ok(staked)
59}
60
61/// Converts a vector of staked assignments into ones with ratio values.
62///
63/// Note that this will NOT attempt at normalizing the result.
64pub fn assignment_staked_to_ratio<A: IdentifierT, P: PerThing>(
65	staked: Vec<StakedAssignment<A>>,
66) -> Vec<Assignment<A, P>> {
67	staked.into_iter().map(|a| a.into_assignment()).collect()
68}
69
70/// Same as [`assignment_staked_to_ratio`] and try and do normalization.
71pub fn assignment_staked_to_ratio_normalized<A: IdentifierT, P: PerThing128>(
72	staked: Vec<StakedAssignment<A>>,
73) -> Result<Vec<Assignment<A, P>>, Error> {
74	let mut ratio = staked.into_iter().map(|a| a.into_assignment()).collect::<Vec<_>>();
75	for assignment in ratio.iter_mut() {
76		assignment.try_normalize().map_err(|_| Error::ArithmeticError)?;
77	}
78	Ok(ratio)
79}
80
81/// Convert some [`Supports`]s into vector of [`StakedAssignment`]
82pub fn supports_to_staked_assignment<A: IdentifierT>(
83	supports: Supports<A>,
84) -> Vec<StakedAssignment<A>> {
85	let mut staked: BTreeMap<A, Vec<(A, ExtendedBalance)>> = BTreeMap::new();
86	for (target, support) in supports {
87		for (voter, amount) in support.voters {
88			staked.entry(voter).or_default().push((target.clone(), amount))
89		}
90	}
91
92	staked
93		.into_iter()
94		.map(|(who, distribution)| StakedAssignment { who, distribution })
95		.collect::<Vec<_>>()
96}
97
98#[cfg(test)]
99mod tests {
100	use super::*;
101	use sp_arithmetic::Perbill;
102
103	#[test]
104	fn into_staked_works() {
105		let assignments = vec![
106			Assignment {
107				who: 1u32,
108				distribution: vec![
109					(10u32, Perbill::from_float(0.5)),
110					(20, Perbill::from_float(0.5)),
111				],
112			},
113			Assignment {
114				who: 2u32,
115				distribution: vec![
116					(10, Perbill::from_float(0.33)),
117					(20, Perbill::from_float(0.67)),
118				],
119			},
120		];
121
122		let stake_of = |_: &u32| -> VoteWeight { 100 };
123		let staked = assignment_ratio_to_staked(assignments, stake_of);
124
125		assert_eq!(
126			staked,
127			vec![
128				StakedAssignment { who: 1u32, distribution: vec![(10u32, 50), (20, 50),] },
129				StakedAssignment { who: 2u32, distribution: vec![(10u32, 33), (20, 67),] }
130			]
131		);
132	}
133}