mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-23 09:41:07 +00:00
Make perthings operate in type operator (#2501)
* perthings operate in type operator * implementation with rem * fmt * doc * better fmt * bump version * Tests for pet-things * demonstrate output as type of operation * Remove redundant assertions. * rename test * update lock * bump impl version
This commit is contained in:
Generated
+1
@@ -3295,6 +3295,7 @@ dependencies = [
|
|||||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"primitive-types 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"sr-io 2.0.0",
|
"sr-io 2.0.0",
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ log = { version = "0.4", optional = true }
|
|||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
primitive-types = "0.2"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ pub use serde;
|
|||||||
pub use runtime_io::{StorageOverlay, ChildrenStorageOverlay};
|
pub use runtime_io::{StorageOverlay, ChildrenStorageOverlay};
|
||||||
|
|
||||||
use rstd::prelude::*;
|
use rstd::prelude::*;
|
||||||
|
use rstd::ops;
|
||||||
use substrate_primitives::{crypto, ed25519, sr25519, hash::{H256, H512}};
|
use substrate_primitives::{crypto, ed25519, sr25519, hash::{H256, H512}};
|
||||||
use codec::{Encode, Decode};
|
use codec::{Encode, Decode};
|
||||||
|
|
||||||
@@ -116,24 +117,52 @@ pub type ConsensusEngineId = [u8; 4];
|
|||||||
pub struct Permill(u32);
|
pub struct Permill(u32);
|
||||||
|
|
||||||
impl Permill {
|
impl Permill {
|
||||||
/// Wraps the argument into `Permill` type.
|
/// Nothing.
|
||||||
pub fn from_millionths(x: u32) -> Permill { Permill(x) }
|
pub fn zero() -> Self { Self(0) }
|
||||||
|
|
||||||
/// Converts percents into `Permill`.
|
/// `true` if this is nothing.
|
||||||
pub fn from_percent(x: u32) -> Permill { Permill(x * 10_000) }
|
pub fn is_zero(&self) -> bool { self.0 == 0 }
|
||||||
|
|
||||||
|
/// Everything.
|
||||||
|
pub fn one() -> Self { Self(1_000_000) }
|
||||||
|
|
||||||
|
/// From an explicitly defined number of parts per maximum of the type.
|
||||||
|
pub fn from_parts(x: u32) -> Self { Self(x.min(1_000_000)) }
|
||||||
|
|
||||||
|
/// Converts from a percent. Equal to `x / 100`.
|
||||||
|
pub fn from_percent(x: u32) -> Self { Self(x.min(100) * 10_000) }
|
||||||
|
|
||||||
/// Converts a fraction into `Permill`.
|
/// Converts a fraction into `Permill`.
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub fn from_fraction(x: f64) -> Permill { Permill((x * 1_000_000.0) as u32) }
|
pub fn from_fraction(x: f64) -> Self { Self((x * 1_000_000.0) as u32) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N> ::rstd::ops::Mul<N> for Permill
|
impl<N> ops::Mul<N> for Permill
|
||||||
where
|
where
|
||||||
N: traits::As<u64>
|
N: Clone + traits::As<u64> + ops::Rem<N, Output=N> + ops::Div<N, Output=N>
|
||||||
|
+ ops::Mul<N, Output=N> + ops::Add<N, Output=N>,
|
||||||
{
|
{
|
||||||
type Output = N;
|
type Output = N;
|
||||||
fn mul(self, b: N) -> Self::Output {
|
fn mul(self, b: N) -> Self::Output {
|
||||||
<N as traits::As<u64>>::sa(b.as_().saturating_mul(self.0 as u64) / 1_000_000)
|
let million = <N as traits::As<u64>>::sa(1_000_000);
|
||||||
|
let part = <N as traits::As<u64>>::sa(self.0 as u64);
|
||||||
|
|
||||||
|
let rem_multiplied_divided = {
|
||||||
|
let rem = b.clone().rem(million.clone());
|
||||||
|
|
||||||
|
// `rem` is inferior to one million, thus it fits into u64
|
||||||
|
let rem_u64: u64 = rem.as_();
|
||||||
|
|
||||||
|
// `self` and `rem` are inferior to one million, thus the product fits into u64
|
||||||
|
let rem_multiplied_u64 = rem_u64 * self.0 as u64;
|
||||||
|
|
||||||
|
let rem_multiplied_divided_u64 = rem_multiplied_u64 / 1_000_000;
|
||||||
|
|
||||||
|
// `rem_multiplied_divided` is inferior to b, thus it can be converted back to N type
|
||||||
|
traits::As::sa(rem_multiplied_divided_u64)
|
||||||
|
};
|
||||||
|
|
||||||
|
(b / million) * part + rem_multiplied_divided
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,39 +204,54 @@ pub struct Perbill(u32);
|
|||||||
|
|
||||||
impl Perbill {
|
impl Perbill {
|
||||||
/// Nothing.
|
/// Nothing.
|
||||||
pub fn zero() -> Perbill { Perbill(0) }
|
pub fn zero() -> Self { Self(0) }
|
||||||
|
|
||||||
/// `true` if this is nothing.
|
/// `true` if this is nothing.
|
||||||
pub fn is_zero(&self) -> bool { self.0 == 0 }
|
pub fn is_zero(&self) -> bool { self.0 == 0 }
|
||||||
|
|
||||||
/// Everything.
|
/// Everything.
|
||||||
pub fn one() -> Perbill { Perbill(1_000_000_000) }
|
pub fn one() -> Self { Self(1_000_000_000) }
|
||||||
|
|
||||||
/// Construct new instance where `x` is in billionths. Value equivalent to `x / 1,000,000,000`.
|
/// From an explicitly defined number of parts per maximum of the type.
|
||||||
pub fn from_billionths(x: u32) -> Perbill { Perbill(x.min(1_000_000_000)) }
|
pub fn from_parts(x: u32) -> Self { Self(x.min(1_000_000_000)) }
|
||||||
|
|
||||||
|
/// Converts from a percent. Equal to `x / 100`.
|
||||||
|
pub fn from_percent(x: u32) -> Self { Self(x.min(100) * 10_000_000) }
|
||||||
|
|
||||||
/// Construct new instance where `x` is in millionths. Value equivalent to `x / 1,000,000`.
|
/// Construct new instance where `x` is in millionths. Value equivalent to `x / 1,000,000`.
|
||||||
pub fn from_millionths(x: u32) -> Perbill { Perbill(x.min(1_000_000) * 1000) }
|
pub fn from_millionths(x: u32) -> Self { Self(x.min(1_000_000) * 1000) }
|
||||||
|
|
||||||
/// Construct new instance where `x` is a percent. Value equivalent to `x%`.
|
|
||||||
pub fn from_percent(x: u32) -> Perbill { Perbill(x.min(100) * 10_000_000) }
|
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
/// Construct new instance whose value is equal to `x` (between 0 and 1).
|
/// Construct new instance whose value is equal to `x` (between 0 and 1).
|
||||||
pub fn from_fraction(x: f64) -> Perbill { Perbill((x.max(0.0).min(1.0) * 1_000_000_000.0) as u32) }
|
pub fn from_fraction(x: f64) -> Self { Self((x.max(0.0).min(1.0) * 1_000_000_000.0) as u32) }
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
/// Construct new instance whose value is equal to `n / d` (between 0 and 1).
|
|
||||||
pub fn from_rational(n: f64, d: f64) -> Perbill { Perbill(((n / d).max(0.0).min(1.0) * 1_000_000_000.0) as u32) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N> ::rstd::ops::Mul<N> for Perbill
|
impl<N> ops::Mul<N> for Perbill
|
||||||
where
|
where
|
||||||
N: traits::As<u64>
|
N: Clone + traits::As<u64> + ops::Rem<N, Output=N> + ops::Div<N, Output=N>
|
||||||
|
+ ops::Mul<N, Output=N> + ops::Add<N, Output=N>
|
||||||
{
|
{
|
||||||
type Output = N;
|
type Output = N;
|
||||||
fn mul(self, b: N) -> Self::Output {
|
fn mul(self, b: N) -> Self::Output {
|
||||||
<N as traits::As<u64>>::sa(b.as_().saturating_mul(self.0 as u64) / 1_000_000_000)
|
let billion = <N as traits::As<u64>>::sa(1_000_000_000);
|
||||||
|
let part = <N as traits::As<u64>>::sa(self.0 as u64);
|
||||||
|
|
||||||
|
let rem_multiplied_divided = {
|
||||||
|
let rem = b.clone().rem(billion.clone());
|
||||||
|
|
||||||
|
// `rem` is inferior to one billion, thus it fits into u64
|
||||||
|
let rem_u64: u64 = rem.as_();
|
||||||
|
|
||||||
|
// `self` and `rem` are inferior to one billion, thus the product fits into u64
|
||||||
|
let rem_multiplied_u64 = rem_u64 * self.0 as u64;
|
||||||
|
|
||||||
|
let rem_multiplied_divided_u64 = rem_multiplied_u64 / 1_000_000_000;
|
||||||
|
|
||||||
|
// `rem_multiplied_divided` is inferior to b, thus it can be converted back to N type
|
||||||
|
traits::As::sa(rem_multiplied_divided_u64)
|
||||||
|
};
|
||||||
|
|
||||||
|
(b / billion) * part + rem_multiplied_divided
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,11 +297,14 @@ impl PerU128 {
|
|||||||
/// Nothing.
|
/// Nothing.
|
||||||
pub fn zero() -> Self { Self(0) }
|
pub fn zero() -> Self { Self(0) }
|
||||||
|
|
||||||
|
/// `true` if this is nothing.
|
||||||
|
pub fn is_zero(&self) -> bool { self.0 == 0 }
|
||||||
|
|
||||||
/// Everything.
|
/// Everything.
|
||||||
pub fn one() -> Self { Self(U128) }
|
pub fn one() -> Self { Self(U128) }
|
||||||
|
|
||||||
/// Construct new instance where `x` is parts in u128::max_value. Equal to x/U128::max_value.
|
/// From an explicitly defined number of parts per maximum of the type.
|
||||||
pub fn from_max_value(x: u128) -> Self { Self(x) }
|
pub fn from_parts(x: u128) -> Self { Self(x) }
|
||||||
|
|
||||||
/// Construct new instance where `x` is denominator and the nominator is 1.
|
/// Construct new instance where `x` is denominator and the nominator is 1.
|
||||||
pub fn from_xth(x: u128) -> Self { Self(U128/x.max(1)) }
|
pub fn from_xth(x: u128) -> Self { Self(U128/x.max(1)) }
|
||||||
@@ -738,6 +785,24 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! per_thing_mul_upper_test {
|
||||||
|
($num_type:tt, $per:tt) => {
|
||||||
|
// all sort of from_percent
|
||||||
|
assert_eq!($per::from_percent(100) * $num_type::max_value(), $num_type::max_value());
|
||||||
|
assert_eq!(
|
||||||
|
$per::from_percent(99) * $num_type::max_value(),
|
||||||
|
((Into::<U256>::into($num_type::max_value()) * 99u32) / 100u32).as_u128() as $num_type
|
||||||
|
);
|
||||||
|
assert_eq!($per::from_percent(50) * $num_type::max_value(), $num_type::max_value() / 2);
|
||||||
|
assert_eq!($per::from_percent(1) * $num_type::max_value(), $num_type::max_value() / 100);
|
||||||
|
assert_eq!($per::from_percent(0) * $num_type::max_value(), 0);
|
||||||
|
|
||||||
|
// bounds
|
||||||
|
assert_eq!($per::one() * $num_type::max_value(), $num_type::max_value());
|
||||||
|
assert_eq!($per::zero() * $num_type::max_value(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn impl_outer_log_works() {
|
fn impl_outer_log_works() {
|
||||||
// encode/decode regular item
|
// encode/decode regular item
|
||||||
@@ -819,8 +884,41 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn saturating_mul() {
|
fn per_things_should_work() {
|
||||||
assert_eq!(super::Perbill::one() * std::u64::MAX, std::u64::MAX/1_000_000_000);
|
use super::{Perbill, Permill};
|
||||||
assert_eq!(super::Permill::from_percent(100) * std::u64::MAX, std::u64::MAX/1_000_000);
|
use primitive_types::U256;
|
||||||
|
|
||||||
|
per_thing_mul_upper_test!(u32, Perbill);
|
||||||
|
per_thing_mul_upper_test!(u64, Perbill);
|
||||||
|
per_thing_mul_upper_test!(u128, Perbill);
|
||||||
|
|
||||||
|
per_thing_mul_upper_test!(u32, Permill);
|
||||||
|
per_thing_mul_upper_test!(u64, Permill);
|
||||||
|
per_thing_mul_upper_test!(u128, Permill);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn per_things_operate_in_output_type() {
|
||||||
|
use super::Perbill;
|
||||||
|
|
||||||
|
assert_eq!(Perbill::one() * 255_u64, 255);
|
||||||
|
// panics
|
||||||
|
assert_ne!(Perbill::one() * 255_u8, 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn per_things_one_minus_one_part() {
|
||||||
|
use primitive_types::U256;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
super::Perbill::from_parts(999_999_999) * std::u128::MAX,
|
||||||
|
((Into::<U256>::into(std::u128::MAX) * 999_999_999u32) / 1_000_000_000u32).as_u128()
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
super::Permill::from_parts(999_999) * std::u128::MAX,
|
||||||
|
((Into::<U256>::into(std::u128::MAX) * 999_999u32) / 1_000_000u32).as_u128()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,8 +108,8 @@ fn staging_testnet_config_genesis() -> GenesisConfig {
|
|||||||
}),
|
}),
|
||||||
staking: Some(StakingConfig {
|
staking: Some(StakingConfig {
|
||||||
current_era: 0,
|
current_era: 0,
|
||||||
offline_slash: Perbill::from_billionths(1_000_000),
|
offline_slash: Perbill::from_parts(1_000_000),
|
||||||
session_reward: Perbill::from_billionths(2_065),
|
session_reward: Perbill::from_parts(2_065),
|
||||||
current_session_reward: 0,
|
current_session_reward: 0,
|
||||||
validator_count: 7,
|
validator_count: 7,
|
||||||
sessions_per_era: 12,
|
sessions_per_era: 12,
|
||||||
|
|||||||
@@ -434,9 +434,9 @@ decl_storage! {
|
|||||||
/// The length of a staking era in sessions.
|
/// The length of a staking era in sessions.
|
||||||
pub SessionsPerEra get(sessions_per_era) config(): T::BlockNumber = T::BlockNumber::sa(1000);
|
pub SessionsPerEra get(sessions_per_era) config(): T::BlockNumber = T::BlockNumber::sa(1000);
|
||||||
/// Maximum reward, per validator, that is provided per acceptable session.
|
/// Maximum reward, per validator, that is provided per acceptable session.
|
||||||
pub SessionReward get(session_reward) config(): Perbill = Perbill::from_billionths(60);
|
pub SessionReward get(session_reward) config(): Perbill = Perbill::from_parts(60);
|
||||||
/// Slash, per validator that is taken for the first time they are found to be offline.
|
/// Slash, per validator that is taken for the first time they are found to be offline.
|
||||||
pub OfflineSlash get(offline_slash) config(): Perbill = Perbill::from_millionths(1000); // Perbill::from_fraction() is only for std, so use from_millionths().
|
pub OfflineSlash get(offline_slash) config(): Perbill = Perbill::from_millionths(1000);
|
||||||
/// Number of instances of offline reports before slashing begins for validators.
|
/// Number of instances of offline reports before slashing begins for validators.
|
||||||
pub OfflineSlashGrace get(offline_slash_grace) config(): u32;
|
pub OfflineSlashGrace get(offline_slash_grace) config(): u32;
|
||||||
/// The length of the bonding duration in eras.
|
/// The length of the bonding duration in eras.
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ pub fn elect<T: Trait + 'static, FV, FN, FS>(
|
|||||||
let temp =
|
let temp =
|
||||||
n.budget.saturating_mul(SCALE_FACTOR) / c.approval_stake
|
n.budget.saturating_mul(SCALE_FACTOR) / c.approval_stake
|
||||||
* (*n.load / SCALE_FACTOR);
|
* (*n.load / SCALE_FACTOR);
|
||||||
c.score = Fraction::from_max_value((*c.score).saturating_add(temp));
|
c.score = Fraction::from_parts((*c.score).saturating_add(temp));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -196,7 +196,7 @@ pub fn elect<T: Trait + 'static, FV, FN, FS>(
|
|||||||
for n in &mut nominators {
|
for n in &mut nominators {
|
||||||
for e in &mut n.edges {
|
for e in &mut n.edges {
|
||||||
if e.who == winner.who {
|
if e.who == winner.who {
|
||||||
e.load = Fraction::from_max_value(*winner.score - *n.load);
|
e.load = Fraction::from_parts(*winner.score - *n.load);
|
||||||
n.load = winner.score;
|
n.load = winner.score;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user