diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index 12e2e3042d..3658699187 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -3295,6 +3295,7 @@ dependencies = [ "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)", "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_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", diff --git a/substrate/core/sr-primitives/Cargo.toml b/substrate/core/sr-primitives/Cargo.toml index 39ee3d1e85..bb6c7b9951 100644 --- a/substrate/core/sr-primitives/Cargo.toml +++ b/substrate/core/sr-primitives/Cargo.toml @@ -16,6 +16,7 @@ log = { version = "0.4", optional = true } [dev-dependencies] serde_json = "1.0" +primitive-types = "0.2" [features] default = ["std"] diff --git a/substrate/core/sr-primitives/src/lib.rs b/substrate/core/sr-primitives/src/lib.rs index 08c6b3c9a9..65a4f3d822 100644 --- a/substrate/core/sr-primitives/src/lib.rs +++ b/substrate/core/sr-primitives/src/lib.rs @@ -30,6 +30,7 @@ pub use serde; pub use runtime_io::{StorageOverlay, ChildrenStorageOverlay}; use rstd::prelude::*; +use rstd::ops; use substrate_primitives::{crypto, ed25519, sr25519, hash::{H256, H512}}; use codec::{Encode, Decode}; @@ -116,24 +117,52 @@ pub type ConsensusEngineId = [u8; 4]; pub struct Permill(u32); impl Permill { - /// Wraps the argument into `Permill` type. - pub fn from_millionths(x: u32) -> Permill { Permill(x) } + /// Nothing. + pub fn zero() -> Self { Self(0) } - /// Converts percents into `Permill`. - pub fn from_percent(x: u32) -> Permill { Permill(x * 10_000) } + /// `true` if this is nothing. + 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`. #[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 ::rstd::ops::Mul for Permill +impl ops::Mul for Permill where - N: traits::As + N: Clone + traits::As + ops::Rem + ops::Div + + ops::Mul + ops::Add, { type Output = N; fn mul(self, b: N) -> Self::Output { - >::sa(b.as_().saturating_mul(self.0 as u64) / 1_000_000) + let million = >::sa(1_000_000); + let part = >::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 { /// Nothing. - pub fn zero() -> Perbill { Perbill(0) } + pub fn zero() -> Self { Self(0) } /// `true` if this is nothing. pub fn is_zero(&self) -> bool { self.0 == 0 } /// 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`. - pub fn from_billionths(x: u32) -> Perbill { Perbill(x.min(1_000_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_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`. - pub fn from_millionths(x: u32) -> Perbill { Perbill(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) } + pub fn from_millionths(x: u32) -> Self { Self(x.min(1_000_000) * 1000) } #[cfg(feature = "std")] /// 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) } - - #[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) } + pub fn from_fraction(x: f64) -> Self { Self((x.max(0.0).min(1.0) * 1_000_000_000.0) as u32) } } -impl ::rstd::ops::Mul for Perbill +impl ops::Mul for Perbill where - N: traits::As + N: Clone + traits::As + ops::Rem + ops::Div + + ops::Mul + ops::Add { type Output = N; fn mul(self, b: N) -> Self::Output { - >::sa(b.as_().saturating_mul(self.0 as u64) / 1_000_000_000) + let billion = >::sa(1_000_000_000); + let part = >::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. 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(U128) } - /// Construct new instance where `x` is parts in u128::max_value. Equal to x/U128::max_value. - pub fn from_max_value(x: u128) -> Self { Self(x) } + /// From an explicitly defined number of parts per maximum of the type. + pub fn from_parts(x: u128) -> Self { Self(x) } /// Construct new instance where `x` is denominator and the nominator is 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::::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] fn impl_outer_log_works() { // encode/decode regular item @@ -819,8 +884,41 @@ mod tests { } #[test] - fn saturating_mul() { - assert_eq!(super::Perbill::one() * std::u64::MAX, std::u64::MAX/1_000_000_000); - assert_eq!(super::Permill::from_percent(100) * std::u64::MAX, std::u64::MAX/1_000_000); + fn per_things_should_work() { + use super::{Perbill, Permill}; + 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::::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::::into(std::u128::MAX) * 999_999u32) / 1_000_000u32).as_u128() + ); } } diff --git a/substrate/node/cli/src/chain_spec.rs b/substrate/node/cli/src/chain_spec.rs index 0d0ab5c305..336636fef8 100644 --- a/substrate/node/cli/src/chain_spec.rs +++ b/substrate/node/cli/src/chain_spec.rs @@ -108,8 +108,8 @@ fn staging_testnet_config_genesis() -> GenesisConfig { }), staking: Some(StakingConfig { current_era: 0, - offline_slash: Perbill::from_billionths(1_000_000), - session_reward: Perbill::from_billionths(2_065), + offline_slash: Perbill::from_parts(1_000_000), + session_reward: Perbill::from_parts(2_065), current_session_reward: 0, validator_count: 7, sessions_per_era: 12, diff --git a/substrate/srml/staking/src/lib.rs b/substrate/srml/staking/src/lib.rs index ec77eab06f..93bd941092 100644 --- a/substrate/srml/staking/src/lib.rs +++ b/substrate/srml/staking/src/lib.rs @@ -434,9 +434,9 @@ decl_storage! { /// The length of a staking era in sessions. pub SessionsPerEra get(sessions_per_era) config(): T::BlockNumber = T::BlockNumber::sa(1000); /// 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. - 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. pub OfflineSlashGrace get(offline_slash_grace) config(): u32; /// The length of the bonding duration in eras. diff --git a/substrate/srml/staking/src/phragmen.rs b/substrate/srml/staking/src/phragmen.rs index 39fa2e9741..56f6419c06 100644 --- a/substrate/srml/staking/src/phragmen.rs +++ b/substrate/srml/staking/src/phragmen.rs @@ -180,7 +180,7 @@ pub fn elect( let temp = n.budget.saturating_mul(SCALE_FACTOR) / c.approval_stake * (*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( for n in &mut nominators { for e in &mut n.edges { 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; } }