mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-27 08:07:58 +00:00
60e5011c72
* Adding first rough ouline of the repository structure * Remove old CI stuff * add title * formatting fixes * move node-exits job's script to scripts dir * Move docs into subdir * move to bin * move maintainence scripts, configs and helpers into its own dir * add .local to ignore * move core->client * start up 'test' area * move test client * move test runtime * make test move compile * Add dependencies rule enforcement. * Fix indexing. * Update docs to reflect latest changes * Moving /srml->/paint * update docs * move client/sr-* -> primitives/ * clean old readme * remove old broken code in rhd * update lock * Step 1. * starting to untangle client * Fix after merge. * start splitting out client interfaces * move children and blockchain interfaces * Move trie and state-machine to primitives. * Fix WASM builds. * fixing broken imports * more interface moves * move backend and light to interfaces * move CallExecutor * move cli off client * moving around more interfaces * re-add consensus crates into the mix * fix subkey path * relieve client from executor * starting to pull out client from grandpa * move is_decendent_of out of client * grandpa still depends on client directly * lemme tests pass * rename srml->paint * Make it compile. * rename interfaces->client-api * Move keyring to primitives. * fixup libp2p dep * fix broken use * allow dependency enforcement to fail * move fork-tree * Moving wasm-builder * make env * move build-script-utils * fixup broken crate depdencies and names * fix imports for authority discovery * fix typo * update cargo.lock * fixing imports * Fix paths and add missing crates * re-add missing crates
521 lines
16 KiB
Rust
521 lines
16 KiB
Rust
// Copyright 2019 Parity Technologies (UK) Ltd.
|
|
// This file is part of Substrate.
|
|
|
|
// Substrate is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
|
|
// Substrate is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#[cfg(feature = "std")]
|
|
use serde::{Serialize, Deserialize};
|
|
|
|
use rstd::{ops, prelude::*, convert::TryInto};
|
|
use codec::{Encode, Decode, CompactAs};
|
|
use crate::traits::{SaturatedConversion, UniqueSaturatedInto, Saturating};
|
|
use substrate_debug_derive::RuntimeDebug;
|
|
|
|
macro_rules! implement_per_thing {
|
|
($name:ident, $test_mod:ident, [$($test_units:tt),+], $max:tt, $type:ty, $upper_type:ty, $title:expr $(,)?) => {
|
|
/// A fixed point representation of a number between in the range [0, 1].
|
|
///
|
|
#[doc = $title]
|
|
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Ord, PartialOrd))]
|
|
#[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq, RuntimeDebug, CompactAs)]
|
|
pub struct $name($type);
|
|
|
|
impl $name {
|
|
/// Nothing.
|
|
pub fn zero() -> Self { Self(0) }
|
|
|
|
/// `true` if this is nothing.
|
|
pub fn is_zero(&self) -> bool { self.0 == 0 }
|
|
|
|
/// Everything.
|
|
pub fn one() -> Self { Self($max) }
|
|
|
|
/// Consume self and deconstruct into a raw numeric type.
|
|
pub fn deconstruct(self) -> $type { self.0 }
|
|
|
|
/// Return the scale at which this per-thing is working.
|
|
pub const fn accuracy() -> $type { $max }
|
|
|
|
/// From an explicitly defined number of parts per maximum of the type.
|
|
///
|
|
/// This can be called at compile time.
|
|
pub const fn from_parts(parts: $type) -> Self {
|
|
Self([parts, $max][(parts > $max) as usize])
|
|
}
|
|
|
|
/// Converts from a percent. Equal to `x / 100`.
|
|
///
|
|
/// This can be created at compile time.
|
|
pub const fn from_percent(x: $type) -> Self {
|
|
Self([x, 100][(x > 100) as usize] * ($max / 100))
|
|
}
|
|
|
|
/// Return the product of multiplication of this value by itself.
|
|
pub fn square(self) -> Self {
|
|
// both can be safely casted and multiplied.
|
|
let p: $upper_type = self.0 as $upper_type * self.0 as $upper_type;
|
|
let q: $upper_type = <$upper_type>::from($max) * <$upper_type>::from($max);
|
|
Self::from_rational_approximation(p, q)
|
|
}
|
|
|
|
/// Converts a fraction into `Permill`.
|
|
#[cfg(feature = "std")]
|
|
pub fn from_fraction(x: f64) -> Self { Self((x * ($max as f64)) as $type) }
|
|
|
|
/// Approximate the fraction `p/q` into a per-thing fraction. This will never overflow.
|
|
///
|
|
/// The computation of this approximation is performed in the generic type `N`. Given
|
|
/// `M` as the data type that can hold the maximum value of this per-thing (e.g. u32 for
|
|
/// perbill), this can only work if `N == M` or `N: From<M> + TryInto<M>`.
|
|
pub fn from_rational_approximation<N>(p: N, q: N) -> Self
|
|
where N: Clone + Ord + From<$type> + TryInto<$type> + ops::Div<N, Output=N>
|
|
{
|
|
// q cannot be zero.
|
|
let q = q.max((1 as $type).into());
|
|
// p should not be bigger than q.
|
|
let p = p.min(q.clone());
|
|
|
|
let factor = (q.clone() / $max.into()).max((1 as $type).into());
|
|
|
|
// q cannot overflow: (q / (q/$max)) < 2 * $max. p < q hence p also cannot overflow.
|
|
// this implies that $type must be able to fit 2 * $max.
|
|
let q_reduce: $type = (q / factor.clone())
|
|
.try_into()
|
|
.map_err(|_| "Failed to convert")
|
|
.expect(
|
|
"q / (q/$max) < (2 * $max). Macro prevents any type being created that \
|
|
does not satisfy this; qed"
|
|
);
|
|
let p_reduce: $type = (p / factor.clone())
|
|
.try_into()
|
|
.map_err(|_| "Failed to convert")
|
|
.expect(
|
|
"q / (q/$max) < (2 * $max). Macro prevents any type being created that \
|
|
does not satisfy this; qed"
|
|
);
|
|
|
|
// `p_reduced` and `q_reduced` are withing $type. Mul by another $max will always
|
|
// fit in $upper_type. This is guaranteed by the macro tests.
|
|
let part =
|
|
p_reduce as $upper_type
|
|
* <$upper_type>::from($max)
|
|
/ q_reduce as $upper_type;
|
|
|
|
$name(part as $type)
|
|
}
|
|
}
|
|
|
|
impl Saturating for $name {
|
|
fn saturating_add(self, rhs: Self) -> Self {
|
|
// defensive-only: since `$max * 2 < $type::max_value()`, this can never overflow.
|
|
Self::from_parts(self.0.saturating_add(rhs.0))
|
|
}
|
|
fn saturating_sub(self, rhs: Self) -> Self {
|
|
Self::from_parts(self.0.saturating_sub(rhs.0))
|
|
}
|
|
fn saturating_mul(self, rhs: Self) -> Self {
|
|
let a = self.0 as $upper_type;
|
|
let b = rhs.0 as $upper_type;
|
|
let m = <$upper_type>::from($max);
|
|
let parts = a * b / m;
|
|
// This will always fit into $type.
|
|
Self::from_parts(parts as $type)
|
|
}
|
|
}
|
|
|
|
impl ops::Div for $name {
|
|
type Output = Self;
|
|
|
|
fn div(self, rhs: Self) -> Self::Output {
|
|
let p = self.0;
|
|
let q = rhs.0;
|
|
Self::from_rational_approximation(p, q)
|
|
}
|
|
}
|
|
|
|
/// Overflow-prune multiplication.
|
|
///
|
|
/// tailored to be used with a balance type.
|
|
impl<N> ops::Mul<N> for $name
|
|
where
|
|
N: Clone + From<$type> + UniqueSaturatedInto<$type> + ops::Rem<N, Output=N>
|
|
+ ops::Div<N, Output=N> + ops::Mul<N, Output=N> + ops::Add<N, Output=N>,
|
|
{
|
|
type Output = N;
|
|
fn mul(self, b: N) -> Self::Output {
|
|
let maximum: N = $max.into();
|
|
let upper_max: $upper_type = $max.into();
|
|
let part: N = self.0.into();
|
|
|
|
let rem_multiplied_divided = {
|
|
let rem = b.clone().rem(maximum.clone());
|
|
|
|
// `rem_sized` is inferior to $max, thus it fits into $type. This is assured by
|
|
// a test.
|
|
let rem_sized = rem.saturated_into::<$type>();
|
|
|
|
// `self` and `rem_sized` are inferior to $max, thus the product is less than
|
|
// $max^2 and fits into $upper_type. This is assured by a test.
|
|
let rem_multiplied_upper = rem_sized as $upper_type * self.0 as $upper_type;
|
|
|
|
// `rem_multiplied_upper` is less than $max^2 therefore divided by $max it fits
|
|
// in $type. remember that $type always fits $max.
|
|
let mut rem_multiplied_divided_sized =
|
|
(rem_multiplied_upper / upper_max) as $type;
|
|
// fix a tiny rounding error
|
|
if rem_multiplied_upper % upper_max > upper_max / 2 {
|
|
rem_multiplied_divided_sized += 1;
|
|
}
|
|
|
|
// `rem_multiplied_divided_sized` is inferior to b, thus it can be converted
|
|
// back to N type
|
|
rem_multiplied_divided_sized.into()
|
|
};
|
|
|
|
(b / maximum) * part + rem_multiplied_divided
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod $test_mod {
|
|
use codec::{Encode, Decode};
|
|
use super::{$name, Saturating, RuntimeDebug};
|
|
use crate::traits::Zero;
|
|
|
|
|
|
#[test]
|
|
fn macro_expanded_correctly() {
|
|
// needed for the `from_percent` to work.
|
|
assert!($max >= 100);
|
|
assert!($max % 100 == 0);
|
|
|
|
// needed for `from_rational_approximation`
|
|
assert!(2 * $max < <$type>::max_value());
|
|
assert!(<$upper_type>::from($max) < <$upper_type>::max_value());
|
|
|
|
// for something like percent they can be the same.
|
|
assert!((<$type>::max_value() as $upper_type) <= <$upper_type>::max_value());
|
|
assert!(<$upper_type>::from($max).checked_mul($max.into()).is_some());
|
|
}
|
|
|
|
#[derive(Encode, Decode, PartialEq, Eq, RuntimeDebug)]
|
|
struct WithCompact<T: codec::HasCompact> {
|
|
data: T,
|
|
}
|
|
|
|
#[test]
|
|
fn has_compact() {
|
|
let data = WithCompact { data: $name(1) };
|
|
let encoded = data.encode();
|
|
assert_eq!(data, WithCompact::<$name>::decode(&mut &encoded[..]).unwrap());
|
|
}
|
|
|
|
#[test]
|
|
fn compact_encoding() {
|
|
let tests = [
|
|
// assume all per_things have the size u8 at least.
|
|
(0 as $type, 1usize),
|
|
(1 as $type, 1usize),
|
|
(63, 1),
|
|
(64, 2),
|
|
(65, 2),
|
|
(<$type>::max_value(), <$type>::max_value().encode().len() + 1)
|
|
];
|
|
for &(n, l) in &tests {
|
|
let compact: codec::Compact<$name> = $name(n).into();
|
|
let encoded = compact.encode();
|
|
assert_eq!(encoded.len(), l);
|
|
let decoded = <codec::Compact<$name>>::decode(&mut & encoded[..])
|
|
.unwrap();
|
|
let per_thingy: $name = decoded.into();
|
|
assert_eq!(per_thingy, $name(n));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn per_thing_api_works() {
|
|
// some really basic stuff
|
|
assert_eq!($name::zero(), $name::from_parts(Zero::zero()));
|
|
assert_eq!($name::one(), $name::from_parts($max));
|
|
assert_eq!($name::accuracy(), $max);
|
|
assert_eq!($name::from_percent(0), $name::from_parts(Zero::zero()));
|
|
assert_eq!($name::from_percent(10), $name::from_parts($max / 10));
|
|
assert_eq!($name::from_percent(100), $name::from_parts($max));
|
|
}
|
|
|
|
macro_rules! per_thing_mul_test {
|
|
($num_type:tt) => {
|
|
// multiplication from all sort of from_percent
|
|
assert_eq!(
|
|
$name::from_percent(100) * $num_type::max_value(),
|
|
$num_type::max_value()
|
|
);
|
|
assert_eq_error_rate!(
|
|
$name::from_percent(99) * $num_type::max_value(),
|
|
((Into::<U256>::into($num_type::max_value()) * 99u32) / 100u32).as_u128() as $num_type,
|
|
1,
|
|
);
|
|
assert_eq!(
|
|
$name::from_percent(50) * $num_type::max_value(),
|
|
$num_type::max_value() / 2,
|
|
);
|
|
assert_eq_error_rate!(
|
|
$name::from_percent(1) * $num_type::max_value(),
|
|
$num_type::max_value() / 100,
|
|
1,
|
|
);
|
|
assert_eq!($name::from_percent(0) * $num_type::max_value(), 0);
|
|
|
|
// // multiplication with bounds
|
|
assert_eq!($name::one() * $num_type::max_value(), $num_type::max_value());
|
|
assert_eq!($name::zero() * $num_type::max_value(), 0);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn per_thing_mul_works() {
|
|
use primitive_types::U256;
|
|
|
|
// accuracy test
|
|
assert_eq!($name::from_rational_approximation(1 as $type, 3) * 30 as $type, 10);
|
|
|
|
$(per_thing_mul_test!($test_units);)*
|
|
}
|
|
|
|
#[test]
|
|
fn per_thing_mul_rounds_to_nearest_number() {
|
|
assert_eq!($name::from_percent(33) * 10u64, 3);
|
|
assert_eq!($name::from_percent(34) * 10u64, 3);
|
|
assert_eq!($name::from_percent(35) * 10u64, 3);
|
|
assert_eq!($name::from_percent(36) * 10u64, 4);
|
|
assert_eq!($name::from_percent(36) * 10u64, 4);
|
|
}
|
|
|
|
#[test]
|
|
fn per_thing_multiplication_with_large_number() {
|
|
use primitive_types::U256;
|
|
let max_minus_one = $max - 1;
|
|
assert_eq_error_rate!(
|
|
$name::from_parts(max_minus_one) * std::u128::MAX,
|
|
((Into::<U256>::into(std::u128::MAX) * max_minus_one) / $max).as_u128(),
|
|
1,
|
|
);
|
|
}
|
|
|
|
macro_rules! per_thing_from_rationale_approx_test {
|
|
($num_type:tt) => {
|
|
// within accuracy boundary
|
|
assert_eq!(
|
|
$name::from_rational_approximation(1 as $num_type, 0),
|
|
$name::one(),
|
|
);
|
|
assert_eq!(
|
|
$name::from_rational_approximation(1 as $num_type, 1),
|
|
$name::one(),
|
|
);
|
|
assert_eq_error_rate!(
|
|
$name::from_rational_approximation(1 as $num_type, 3).0,
|
|
$name::from_parts($max / 3).0,
|
|
2
|
|
);
|
|
assert_eq!(
|
|
$name::from_rational_approximation(1 as $num_type, 10),
|
|
$name::from_percent(10),
|
|
);
|
|
assert_eq!(
|
|
$name::from_rational_approximation(1 as $num_type, 4),
|
|
$name::from_percent(25),
|
|
);
|
|
assert_eq!(
|
|
$name::from_rational_approximation(1 as $num_type, 4),
|
|
$name::from_rational_approximation(2 as $num_type, 8),
|
|
);
|
|
// no accurate anymore but won't overflow.
|
|
assert_eq!(
|
|
$name::from_rational_approximation(
|
|
$num_type::max_value() - 1,
|
|
$num_type::max_value()
|
|
),
|
|
$name::one(),
|
|
);
|
|
assert_eq_error_rate!(
|
|
$name::from_rational_approximation(
|
|
$num_type::max_value() / 3,
|
|
$num_type::max_value()
|
|
).0,
|
|
$name::from_parts($max / 3).0,
|
|
2
|
|
);
|
|
assert_eq!(
|
|
$name::from_rational_approximation(1, $num_type::max_value()),
|
|
$name::zero(),
|
|
);
|
|
};
|
|
}
|
|
|
|
#[test]
|
|
fn per_thing_from_rationale_approx_works() {
|
|
// This is just to make sure something like Percent which _might_ get built from a
|
|
// u8 does not overflow in the context of this test.
|
|
let max_value = <$upper_type>::from($max);
|
|
// almost at the edge
|
|
assert_eq!(
|
|
$name::from_rational_approximation($max - 1, $max + 1),
|
|
$name::from_parts($max - 2),
|
|
);
|
|
assert_eq!(
|
|
$name::from_rational_approximation(1, $max-1),
|
|
$name::from_parts(1),
|
|
);
|
|
assert_eq!(
|
|
$name::from_rational_approximation(1, $max),
|
|
$name::from_parts(1),
|
|
);
|
|
assert_eq!(
|
|
$name::from_rational_approximation(2, 2 * $max - 1),
|
|
$name::from_parts(1),
|
|
);
|
|
assert_eq!(
|
|
$name::from_rational_approximation(1, $max+1),
|
|
$name::zero(),
|
|
);
|
|
assert_eq!(
|
|
$name::from_rational_approximation(3 * max_value / 2, 3 * max_value),
|
|
$name::from_percent(50),
|
|
);
|
|
$(per_thing_from_rationale_approx_test!($test_units);)*
|
|
}
|
|
|
|
#[test]
|
|
fn per_things_mul_operates_in_output_type() {
|
|
// assert_eq!($name::from_percent(50) * 100u32, 50u32);
|
|
assert_eq!($name::from_percent(50) * 100u64, 50u64);
|
|
assert_eq!($name::from_percent(50) * 100u128, 50u128);
|
|
}
|
|
|
|
#[test]
|
|
fn per_thing_saturating_op_works() {
|
|
assert_eq!(
|
|
$name::from_percent(50).saturating_add($name::from_percent(40)),
|
|
$name::from_percent(90)
|
|
);
|
|
assert_eq!(
|
|
$name::from_percent(50).saturating_add($name::from_percent(50)),
|
|
$name::from_percent(100)
|
|
);
|
|
assert_eq!(
|
|
$name::from_percent(60).saturating_add($name::from_percent(50)),
|
|
$name::from_percent(100)
|
|
);
|
|
|
|
assert_eq!(
|
|
$name::from_percent(60).saturating_sub($name::from_percent(50)),
|
|
$name::from_percent(10)
|
|
);
|
|
assert_eq!(
|
|
$name::from_percent(60).saturating_sub($name::from_percent(60)),
|
|
$name::from_percent(0)
|
|
);
|
|
assert_eq!(
|
|
$name::from_percent(60).saturating_sub($name::from_percent(70)),
|
|
$name::from_percent(0)
|
|
);
|
|
|
|
assert_eq!(
|
|
$name::from_percent(50).saturating_mul($name::from_percent(50)),
|
|
$name::from_percent(25)
|
|
);
|
|
assert_eq!(
|
|
$name::from_percent(20).saturating_mul($name::from_percent(20)),
|
|
$name::from_percent(4)
|
|
);
|
|
assert_eq!(
|
|
$name::from_percent(10).saturating_mul($name::from_percent(10)),
|
|
$name::from_percent(1)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn per_thing_square_works() {
|
|
assert_eq!($name::from_percent(100).square(), $name::from_percent(100));
|
|
assert_eq!($name::from_percent(50).square(), $name::from_percent(25));
|
|
assert_eq!($name::from_percent(10).square(), $name::from_percent(1));
|
|
assert_eq!(
|
|
$name::from_percent(2).square(),
|
|
$name::from_parts((4 * <$upper_type>::from($max) / 100 / 100) as $type)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn per_things_div_works() {
|
|
// normal
|
|
assert_eq!($name::from_percent(10) / $name::from_percent(20),
|
|
$name::from_percent(50)
|
|
);
|
|
assert_eq!($name::from_percent(10) / $name::from_percent(10),
|
|
$name::from_percent(100)
|
|
);
|
|
assert_eq!($name::from_percent(10) / $name::from_percent(0),
|
|
$name::from_percent(100)
|
|
);
|
|
|
|
// will not overflow
|
|
assert_eq!($name::from_percent(10) / $name::from_percent(5),
|
|
$name::from_percent(100)
|
|
);
|
|
assert_eq!($name::from_percent(100) / $name::from_percent(50),
|
|
$name::from_percent(100)
|
|
);
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
implement_per_thing!(
|
|
Percent,
|
|
test_per_cent,
|
|
[u32, u64, u128],
|
|
100u8,
|
|
u8,
|
|
u16,
|
|
"_Percent_",
|
|
);
|
|
implement_per_thing!(
|
|
Permill,
|
|
test_permill,
|
|
[u32, u64, u128],
|
|
1_000_000u32,
|
|
u32,
|
|
u64,
|
|
"_Parts per Million_",
|
|
);
|
|
implement_per_thing!(
|
|
Perbill,
|
|
test_perbill,
|
|
[u32, u64, u128],
|
|
1_000_000_000u32,
|
|
u32,
|
|
u64,
|
|
"_Parts per Billion_",
|
|
);
|
|
implement_per_thing!(
|
|
Perquintill,
|
|
test_perquintill,
|
|
[u64, u128],
|
|
1_000_000_000_000_000_000u64,
|
|
u64,
|
|
u128,
|
|
"_Parts per Quintillion_",
|
|
);
|