referrerpolicy=no-referrer-when-downgrade

sp_staking/
currency_to_vote.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
18use sp_runtime::{
19	traits::{UniqueSaturatedFrom, UniqueSaturatedInto},
20	SaturatedConversion,
21};
22
23/// A trait similar to `Convert` to convert values from `B` an abstract balance type
24/// into u64 and back from u128. (This conversion is used in election and other places where complex
25/// calculation over balance type is needed)
26///
27/// Total issuance of the currency is passed in, but an implementation of this trait may or may not
28/// use it.
29///
30/// # WARNING
31///
32/// the total issuance being passed in implies that the implementation must be aware of the fact
33/// that its values can affect the outcome. This implies that if the vote value is dependent on the
34/// total issuance, it should never ber written to storage for later re-use.
35pub trait CurrencyToVote<B> {
36	/// Convert balance to u64.
37	fn to_vote(value: B, issuance: B) -> u64;
38
39	/// Convert u128 to balance.
40	fn to_currency(value: u128, issuance: B) -> B;
41
42	/// Send a signal whether you are going to downscale the `B` when converting to `u64` given the
43	/// current issuance.
44	///
45	/// This is useful for automated checks in place to signal maintainers that the total issuance
46	/// has reached a point where downscaling will happen.
47	///
48	/// `None` means we don't know. `Some(_)` means we know with certainty.
49	fn will_downscale(issuance: B) -> Option<bool>;
50}
51
52/// An implementation of `CurrencyToVote` tailored for chain's that have a balance type of u128.
53///
54/// The factor is the `(total_issuance / u64::MAX).max(1)`, represented as u64. Let's look at the
55/// important cases:
56///
57/// If the chain's total issuance is less than u64::MAX, this will always be 1, which means that
58/// the factor will not have any effect. In this case, any account's balance is also less. Thus,
59/// both of the conversions are basically an `as`; Any balance can fit in u64.
60///
61/// If the chain's total issuance is more than 2*u64::MAX, then a factor might be multiplied and
62/// divided upon conversion.
63pub struct U128CurrencyToVote;
64
65impl U128CurrencyToVote {
66	fn factor(issuance: u128) -> u128 {
67		(issuance / u64::MAX as u128).max(1)
68	}
69}
70
71impl CurrencyToVote<u128> for U128CurrencyToVote {
72	fn to_vote(value: u128, issuance: u128) -> u64 {
73		(value / Self::factor(issuance)).saturated_into()
74	}
75
76	fn to_currency(value: u128, issuance: u128) -> u128 {
77		value.saturating_mul(Self::factor(issuance))
78	}
79
80	fn will_downscale(issuance: u128) -> Option<bool> {
81		Some(issuance > u64::MAX as u128)
82	}
83}
84
85/// A naive implementation of `CurrencyConvert` that simply saturates all conversions.
86///
87/// # Warning
88///
89/// This is designed to be used mostly for testing. Use with care, and think about the consequences.
90pub struct SaturatingCurrencyToVote;
91
92impl<B: UniqueSaturatedInto<u64> + UniqueSaturatedFrom<u128>> CurrencyToVote<B>
93	for SaturatingCurrencyToVote
94{
95	fn to_vote(value: B, _: B) -> u64 {
96		value.unique_saturated_into()
97	}
98
99	fn to_currency(value: u128, _: B) -> B {
100		B::unique_saturated_from(value)
101	}
102
103	fn will_downscale(_issuance: B) -> Option<bool> {
104		None
105	}
106}
107
108#[cfg(feature = "std")]
109impl<B: UniqueSaturatedInto<u64> + UniqueSaturatedFrom<u128>> CurrencyToVote<B> for () {
110	fn to_vote(value: B, issuance: B) -> u64 {
111		SaturatingCurrencyToVote::to_vote(value, issuance)
112	}
113
114	/// Convert u128 to balance.
115	fn to_currency(value: u128, issuance: B) -> B {
116		SaturatingCurrencyToVote::to_currency(value, issuance)
117	}
118
119	fn will_downscale(_issuance: B) -> Option<bool> {
120		None
121	}
122}