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
43/// An implementation of `CurrencyToVote` tailored for chain's that have a balance type of u128.
44///
45/// The factor is the `(total_issuance / u64::MAX).max(1)`, represented as u64. Let's look at the
46/// important cases:
47///
48/// If the chain's total issuance is less than u64::MAX, this will always be 1, which means that
49/// the factor will not have any effect. In this case, any account's balance is also less. Thus,
50/// both of the conversions are basically an `as`; Any balance can fit in u64.
51///
52/// If the chain's total issuance is more than 2*u64::MAX, then a factor might be multiplied and
53/// divided upon conversion.
54pub struct U128CurrencyToVote;
55
56impl U128CurrencyToVote {
57 fn factor(issuance: u128) -> u128 {
58 (issuance / u64::MAX as u128).max(1)
59 }
60}
61
62impl CurrencyToVote<u128> for U128CurrencyToVote {
63 fn to_vote(value: u128, issuance: u128) -> u64 {
64 (value / Self::factor(issuance)).saturated_into()
65 }
66
67 fn to_currency(value: u128, issuance: u128) -> u128 {
68 value.saturating_mul(Self::factor(issuance))
69 }
70}
71
72/// A naive implementation of `CurrencyConvert` that simply saturates all conversions.
73///
74/// # Warning
75///
76/// This is designed to be used mostly for testing. Use with care, and think about the consequences.
77pub struct SaturatingCurrencyToVote;
78
79impl<B: UniqueSaturatedInto<u64> + UniqueSaturatedFrom<u128>> CurrencyToVote<B>
80 for SaturatingCurrencyToVote
81{
82 fn to_vote(value: B, _: B) -> u64 {
83 value.unique_saturated_into()
84 }
85
86 fn to_currency(value: u128, _: B) -> B {
87 B::unique_saturated_from(value)
88 }
89}
90
91#[cfg(feature = "std")]
92impl<B: UniqueSaturatedInto<u64> + UniqueSaturatedFrom<u128>> CurrencyToVote<B> for () {
93 fn to_vote(value: B, issuance: B) -> u64 {
94 SaturatingCurrencyToVote::to_vote(value, issuance)
95 }
96
97 /// Convert u128 to balance.
98 fn to_currency(value: u128, issuance: B) -> B {
99 SaturatingCurrencyToVote::to_currency(value, issuance)
100 }
101}