* Start to remove the `As` bound on `SimpleArtithmetic`

This just introduces standard numeric bounds, assuming a minimum of
`u32`. Also included is a saturating from/into trait allowing ergonomic
infallible conversion when you don't care if it saturates.

* Remove As from Balances trait

* Remove As from Aura module

* Remove As from Babe module

* Expunge `As` from contract

* Council module

* Democracy

* Finality tracker

* Grandpa

* First bit of indices

* indices

* Line lengths

* session

* system

* Staking

* Square up all other uses of As.

* RHD update

* Fix build/test

* Remove As trait

* line widths

* Remove final As ref

* Update srml/staking/src/lib.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update core/client/src/cht.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update core/client/db/src/light.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Apply suggestions from code review

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* whitespace

* Apply suggestions from code review

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>
Co-Authored-By: André Silva <andre.beat@gmail.com>

* Bring back u32 check for number on CLI
This commit is contained in:
Gavin Wood
2019-05-22 23:11:38 +01:00
committed by GitHub
parent 36987c0205
commit 3860d7c810
60 changed files with 695 additions and 491 deletions
@@ -22,8 +22,8 @@ use std::fmt;
use rstd::prelude::*;
use runtime_io::blake2_256;
use crate::codec::{Decode, Encode, Input, Compact};
use crate::traits::{self, Member, SimpleArithmetic, MaybeDisplay, CurrentHeight, BlockNumberToHash, Lookup,
Checkable, Extrinsic};
use crate::traits::{self, Member, SimpleArithmetic, MaybeDisplay, CurrentHeight, BlockNumberToHash,
Lookup, Checkable, Extrinsic, SaturatedConversion};
use super::{CheckedExtrinsic, Era};
const TRANSACTION_VERSION: u8 = 1;
@@ -84,7 +84,8 @@ where
fn check(self, context: &Context) -> Result<Self::Checked, &'static str> {
Ok(match self.signature {
Some((signed, signature, index, era)) => {
let h = context.block_number_to_hash(BlockNumber::sa(era.birth(context.current_height().as_())))
let current_u64 = context.current_height().saturated_into::<u64>();
let h = context.block_number_to_hash(era.birth(current_u64).saturated_into())
.ok_or("transaction birth block ancient")?;
let signed = context.lookup(signed)?;
let raw_payload = (index, self.function, era, h);
@@ -22,8 +22,10 @@ use std::fmt;
use rstd::prelude::*;
use runtime_io::blake2_256;
use crate::codec::{Decode, Encode, Input};
use crate::traits::{self, Member, SimpleArithmetic, MaybeDisplay, CurrentHeight, BlockNumberToHash, Lookup,
Checkable, Extrinsic};
use crate::traits::{
self, Member, SimpleArithmetic, MaybeDisplay, CurrentHeight, BlockNumberToHash,
Lookup, Checkable, Extrinsic, SaturatedConversion
};
use super::{CheckedExtrinsic, Era};
const TRANSACTION_VERSION: u8 = 1;
@@ -83,7 +85,8 @@ where
fn check(self, context: &Context) -> Result<Self::Checked, &'static str> {
Ok(match self.signature {
Some((signed, signature, index, era)) => {
let h = context.block_number_to_hash(BlockNumber::sa(era.birth(context.current_height().as_())))
let current_u64 = context.current_height().saturated_into::<u64>();
let h = context.block_number_to_hash(era.birth(current_u64).saturated_into())
.ok_or("transaction birth block ancient")?;
let signed = context.lookup(signed)?;
let raw_payload = (index, self.function, era, h);
+30 -28
View File
@@ -29,8 +29,7 @@ pub use serde;
#[cfg(feature = "std")]
pub use runtime_io::{StorageOverlay, ChildrenStorageOverlay};
use rstd::prelude::*;
use rstd::ops;
use rstd::{prelude::*, ops};
use substrate_primitives::{crypto, ed25519, sr25519, hash::{H256, H512}};
use codec::{Encode, Decode};
@@ -38,6 +37,8 @@ use codec::{Encode, Decode};
pub mod testing;
pub mod traits;
use traits::{SaturatedConversion, UniqueSaturatedInto};
pub mod generic;
pub mod transaction_validity;
@@ -159,27 +160,30 @@ impl Permill {
impl<N> ops::Mul<N> for Permill
where
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>,
N: Clone + From<u32> + UniqueSaturatedInto<u32> + 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 million = <N as traits::As<u64>>::sa(1_000_000);
let part = <N as traits::As<u64>>::sa(self.0 as u64);
let million: N = 1_000_000.into();
let part: N = self.0.into();
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_();
// `rem` is inferior to one million, thus it fits into u32
let rem_u32 = rem.saturated_into::<u32>();
// `self` and `rem` are inferior to one million, thus the product fits into u64
let rem_multiplied_u64 = rem_u64 * self.0 as u64;
// `self` and `rem` are inferior to one million, thus the product is less than 10^12
// and fits into u64
let rem_multiplied_u64 = rem_u32 as u64 * self.0 as u64;
let rem_multiplied_divided_u64 = rem_multiplied_u64 / 1_000_000;
// `rem_multiplied_u64` is less than 10^12 therefore divided by a million it fits into
// u32
let rem_multiplied_divided_u32 = (rem_multiplied_u64 / 1_000_000) as u32;
// `rem_multiplied_divided` is inferior to b, thus it can be converted back to N type
traits::As::sa(rem_multiplied_divided_u64)
rem_multiplied_divided_u32.into()
};
(b / million) * part + rem_multiplied_divided
@@ -248,27 +252,30 @@ impl Perbill {
impl<N> ops::Mul<N> for Perbill
where
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>
N: Clone + From<u32> + UniqueSaturatedInto<u32> + 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 billion = <N as traits::As<u64>>::sa(1_000_000_000);
let part = <N as traits::As<u64>>::sa(self.0 as u64);
let billion: N = 1_000_000_000.into();
let part: N = self.0.into();
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_();
// `rem` is inferior to one billion, thus it fits into u32
let rem_u32 = rem.saturated_into::<u32>();
// `self` and `rem` are inferior to one billion, thus the product fits into u64
let rem_multiplied_u64 = rem_u64 * self.0 as u64;
// `self` and `rem` are inferior to one billion, thus the product is less than 10^18
// and fits into u64
let rem_multiplied_u64 = rem_u32 as u64 * self.0 as u64;
let rem_multiplied_divided_u64 = rem_multiplied_u64 / 1_000_000_000;
// `rem_multiplied_u64` is less than 10^18 therefore divided by a billion it fits into
// u32
let rem_multiplied_divided_u32 = (rem_multiplied_u64 / 1_000_000_000) as u32;
// `rem_multiplied_divided` is inferior to b, thus it can be converted back to N type
traits::As::sa(rem_multiplied_divided_u64)
rem_multiplied_divided_u32.into()
};
(b / billion) * part + rem_multiplied_divided
@@ -918,13 +925,8 @@ mod tests {
}
#[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);
assert_eq!(super::Perbill::one() * 255_u64, 255);
}
#[test]
+121 -49
View File
@@ -17,7 +17,7 @@
//! Primitives for the runtime modules.
use rstd::prelude::*;
use rstd::{self, result, marker::PhantomData};
use rstd::{self, result, marker::PhantomData, convert::{TryFrom, TryInto}};
use runtime_io;
#[cfg(feature = "std")] use std::fmt::{Debug, Display};
#[cfg(feature = "std")] use serde::{Serialize, Deserialize, de::DeserializeOwned};
@@ -27,7 +27,7 @@ use crate::transaction_validity::TransactionValidity;
pub use integer_sqrt::IntegerSquareRoot;
pub use num_traits::{
Zero, One, Bounded, CheckedAdd, CheckedSub, CheckedMul, CheckedDiv,
CheckedShl, CheckedShr, Saturating
CheckedShl, CheckedShr
};
use rstd::ops::{
Add, Sub, Mul, Div, Rem, AddAssign, SubAssign, MulAssign, DivAssign,
@@ -157,71 +157,143 @@ impl<T> Convert<T, T> for Identity {
fn convert(a: T) -> T { a }
}
/// Simple trait similar to `Into`, except that it can be used to convert numerics between each
/// other.
pub trait As<T> {
/// Convert forward (ala `Into::into`).
fn as_(self) -> T;
/// Convert backward (ala `From::from`).
fn sa(_: T) -> Self;
}
macro_rules! impl_numerics {
( $( $t:ty ),* ) => {
$(
impl_numerics!($t: u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize,);
)*
};
( $f:ty : $t:ty, $( $rest:ty, )* ) => {
impl As<$t> for $f {
fn as_(self) -> $t { self as $t }
fn sa(t: $t) -> Self { t as Self }
}
impl_numerics!($f: $( $rest, )*);
};
( $f:ty : ) => {}
}
impl_numerics!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
/// A meta trait for arithmetic.
///
/// Arithmetic types do all the usual stuff you'd expect numbers to do. They are guaranteed to
/// be able to represent at least `u32` values without loss, hence the trait implies `From<u32>`
/// and smaller ints. All other conversions are fallible.
pub trait SimpleArithmetic:
Zero + One + IntegerSquareRoot + As<u64> +
Zero + One + IntegerSquareRoot +
From<u8> + From<u16> + From<u32> + TryInto<u8> + TryInto<u16> + TryInto<u32> +
TryFrom<u64> + TryInto<u64> + TryFrom<u128> + TryInto<u128> + TryFrom<usize> + TryInto<usize> +
UniqueSaturatedInto<u8> + UniqueSaturatedInto<u16> + UniqueSaturatedInto<u32> +
UniqueSaturatedFrom<u64> + UniqueSaturatedInto<u64> + UniqueSaturatedFrom<u128> + UniqueSaturatedInto<u128> +
Add<Self, Output = Self> + AddAssign<Self> +
Sub<Self, Output = Self> + SubAssign<Self> +
Mul<Self, Output = Self> + MulAssign<Self> +
Div<Self, Output = Self> + DivAssign<Self> +
Rem<Self, Output = Self> + RemAssign<Self> +
Shl<u32, Output = Self> + Shr<u32, Output = Self> +
CheckedShl +
CheckedShr +
CheckedAdd +
CheckedSub +
CheckedMul +
CheckedDiv +
Saturating +
PartialOrd<Self> + Ord + Bounded +
HasCompact
CheckedShl + CheckedShr + CheckedAdd + CheckedSub + CheckedMul + CheckedDiv +
Saturating + PartialOrd<Self> + Ord + Bounded +
HasCompact + Sized
{}
impl<T:
Zero + One + IntegerSquareRoot + As<u64> +
Zero + One + IntegerSquareRoot +
From<u8> + From<u16> + From<u32> + TryInto<u8> + TryInto<u16> + TryInto<u32> +
TryFrom<u64> + TryInto<u64> + TryFrom<u128> + TryInto<u128> + TryFrom<usize> + TryInto<usize> +
UniqueSaturatedInto<u8> + UniqueSaturatedInto<u16> + UniqueSaturatedInto<u32> +
UniqueSaturatedFrom<u64> + UniqueSaturatedInto<u64> + UniqueSaturatedFrom<u128> +
UniqueSaturatedInto<u128> + UniqueSaturatedFrom<usize> + UniqueSaturatedInto<usize> +
Add<Self, Output = Self> + AddAssign<Self> +
Sub<Self, Output = Self> + SubAssign<Self> +
Mul<Self, Output = Self> + MulAssign<Self> +
Div<Self, Output = Self> + DivAssign<Self> +
Rem<Self, Output = Self> + RemAssign<Self> +
Shl<u32, Output = Self> + Shr<u32, Output = Self> +
CheckedShl +
CheckedShr +
CheckedAdd +
CheckedSub +
CheckedMul +
CheckedDiv +
Saturating +
PartialOrd<Self> + Ord + Bounded +
HasCompact
CheckedShl + CheckedShr + CheckedAdd + CheckedSub + CheckedMul + CheckedDiv +
Saturating + PartialOrd<Self> + Ord + Bounded +
HasCompact + Sized
> SimpleArithmetic for T {}
/// Just like `From` except that if the source value is too big to fit into the destination type
/// then it'll saturate the destination.
pub trait UniqueSaturatedFrom<T: Sized>: Sized {
/// Convert from a value of `T` into an equivalent instance of `Self`.
fn unique_saturated_from(t: T) -> Self;
}
/// Just like `Into` except that if the source value is too big to fit into the destination type
/// then it'll saturate the destination.
pub trait UniqueSaturatedInto<T: Sized>: Sized {
/// Consume self to return an equivalent value of `T`.
fn unique_saturated_into(self) -> T;
}
impl<T: Sized, S: TryFrom<T> + Bounded + Sized> UniqueSaturatedFrom<T> for S {
fn unique_saturated_from(t: T) -> Self {
S::try_from(t).unwrap_or_else(|_| Bounded::max_value())
}
}
impl<T: Bounded + Sized, S: TryInto<T> + Sized> UniqueSaturatedInto<T> for S {
fn unique_saturated_into(self) -> T {
self.try_into().unwrap_or_else(|_| Bounded::max_value())
}
}
/// Simple trait to use checked mul and max value to give a saturated mul operation over
/// supported types.
pub trait Saturating {
/// Saturated addition - if the product can't fit in the type then just use max-value.
fn saturating_add(self, o: Self) -> Self;
/// Saturated subtraction - if the product can't fit in the type then just use max-value.
fn saturating_sub(self, o: Self) -> Self;
/// Saturated multiply - if the product can't fit in the type then just use max-value.
fn saturating_mul(self, o: Self) -> Self;
}
impl<T: CheckedMul + Bounded + num_traits::Saturating> Saturating for T {
fn saturating_add(self, o: Self) -> Self {
<Self as num_traits::Saturating>::saturating_add(self, o)
}
fn saturating_sub(self, o: Self) -> Self {
<Self as num_traits::Saturating>::saturating_sub(self, o)
}
fn saturating_mul(self, o: Self) -> Self {
self.checked_mul(&o).unwrap_or_else(Bounded::max_value)
}
}
/// Convenience type to work around the highly unergonomic syntax needed
/// to invoke the functions of overloaded generic traits, in this case
/// `SaturatedFrom` and `SaturatedInto`.
pub trait SaturatedConversion {
/// Convert from a value of `T` into an equivalent instance of `Self`.
///
/// This just uses `UniqueSaturatedFrom` internally but with this
/// variant you can provide the destination type using turbofish syntax
/// in case Rust happens not to assume the correct type.
fn saturated_from<T>(t: T) -> Self where Self: UniqueSaturatedFrom<T> {
<Self as UniqueSaturatedFrom<T>>::unique_saturated_from(t)
}
/// Consume self to return an equivalent value of `T`.
///
/// This just uses `UniqueSaturatedInto` internally but with this
/// variant you can provide the destination type using turbofish syntax
/// in case Rust happens not to assume the correct type.
fn saturated_into<T>(self) -> T where Self: UniqueSaturatedInto<T> {
<Self as UniqueSaturatedInto<T>>::unique_saturated_into(self)
}
}
impl<T: Sized> SaturatedConversion for T {}
/// Convenience type to work around the highly unergonomic syntax needed
/// to invoke the functions of overloaded generic traits, in this case
/// `TryFrom` and `TryInto`.
pub trait CheckedConversion {
/// Convert from a value of `T` into an equivalent instance of `Option<Self>`.
///
/// This just uses `TryFrom` internally but with this
/// variant you can provide the destination type using turbofish syntax
/// in case Rust happens not to assume the correct type.
fn checked_from<T>(t: T) -> Option<Self> where Self: TryFrom<T> {
<Self as TryFrom<T>>::try_from(t).ok()
}
/// Consume self to return `Some` equivalent value of `Option<T>`.
///
/// This just uses `TryInto` internally but with this
/// variant you can provide the destination type using turbofish syntax
/// in case Rust happens not to assume the correct type.
fn checked_into<T>(self) -> Option<T> where Self: TryInto<T> {
<Self as TryInto<T>>::try_into(self).ok()
}
}
impl<T: Sized> CheckedConversion for T {}
/// Trait for things that can be clear (have no bits set). For numeric types, essentially the same
/// as `Zero`.
pub trait Clear {