diff --git a/core/src/env/arithmetic.rs b/core/src/env/arithmetic.rs new file mode 100644 index 00000000000..14c43b10826 --- /dev/null +++ b/core/src/env/arithmetic.rs @@ -0,0 +1,232 @@ +// Copyright 2019-2020 Parity Technologies (UK) Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Primitive traits for runtime arithmetic, copied from substrate + +use core::ops::{ + Add, + AddAssign, + Div, + DivAssign, + Mul, + MulAssign, + Sub, + SubAssign, +}; +use num_traits::{ + checked_pow, + Bounded, + CheckedMul, + One, + Unsigned, + Zero, +}; + +/// Types that allow for simple arithmetic operations. +/// +/// Subset of all trait bounds copied over from what Substrate defines +/// for its `BaseArithmetic` types. We can extend this in the future +/// if needed. +pub trait BaseArithmetic: + Sized + + From + + Bounded + + Ord + + PartialOrd + + Zero + + One + + Bounded + + Add + + AddAssign + + Sub + + SubAssign + + Mul + + MulAssign + + Div + + DivAssign + + CheckedMul + + Saturating +// Further trait bounds from the original BaseArithmetic trait +// that we could use to extend ink!'s BaseArithmetic trait. +// +// From + +// From + +// From + +// TryFrom + +// TryFrom + +// TryFrom + +// TryInto + +// TryInto + +// TryInto + +// TryInto + +// TryInto + +// TryInto + +// UniqueSaturatedInto + +// UniqueSaturatedInto + +// UniqueSaturatedInto + +// UniqueSaturatedInto + +// UniqueSaturatedInto + +// UniqueSaturatedFrom + +// UniqueSaturatedFrom + +// Shl + +// Shr + +// CheckedAdd + +// CheckedSub + +// CheckedDiv + +// CheckedShl + +// CheckedShr + +// IntegerSquareRoot + +{ +} + +impl BaseArithmetic for T where + T: Sized + + From + + Bounded + + Ord + + PartialOrd + + Zero + + One + + Add + + AddAssign + + Sub + + SubAssign + + Mul + + MulAssign + + Div + + DivAssign + + CheckedMul + + Saturating +{ +} + +/// A meta trait for arithmetic (copied from substrate). +/// +/// 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` +/// and smaller integers. All other conversions are fallible. +pub trait AtLeast32Bit: BaseArithmetic + From + From {} + +impl AtLeast32Bit for T where T: BaseArithmetic + From + From {} + +/// A meta trait for arithmetic. Same as [`AtLeast32Bit `], but also bounded to be unsigned. +pub trait AtLeast32BitUnsigned: AtLeast32Bit + Unsigned {} + +impl AtLeast32BitUnsigned for T where T: AtLeast32Bit + Unsigned {} + +/// Saturating arithmetic operations, returning maximum or minimum values instead of overflowing. +pub trait Saturating { + /// Saturating addition. Compute `self + rhs`, saturating at the numeric bounds instead of + /// overflowing. + fn saturating_add(self, rhs: Self) -> Self; + + /// Saturating subtraction. Compute `self - rhs`, saturating at the numeric bounds instead of + /// overflowing. + fn saturating_sub(self, rhs: Self) -> Self; + + /// Saturating multiply. Compute `self * rhs`, saturating at the numeric bounds instead of + /// overflowing. + fn saturating_mul(self, rhs: Self) -> Self; + + /// Saturating exponentiation. Compute `self.pow(exp)`, saturating at the numeric bounds + /// instead of overflowing. + fn saturating_pow(self, exp: usize) -> Self; +} + +impl Saturating for T +where + T: Clone + Zero + One + PartialOrd + CheckedMul + Bounded + num_traits::Saturating, +{ + fn saturating_add(self, o: Self) -> Self { + ::saturating_add(self, o) + } + + fn saturating_sub(self, o: Self) -> Self { + ::saturating_sub(self, o) + } + + fn saturating_mul(self, o: Self) -> Self { + self.checked_mul(&o).unwrap_or_else(|| { + if (self < T::zero()) != (o < T::zero()) { + Bounded::min_value() + } else { + Bounded::max_value() + } + }) + } + + fn saturating_pow(self, exp: usize) -> Self { + let neg = self < T::zero() && exp % 2 != 0; + checked_pow(self, exp).unwrap_or_else(|| { + if neg { + Bounded::min_value() + } else { + Bounded::max_value() + } + }) + } +} + +#[cfg(test)] +mod tests { + use super::Saturating; + + #[test] + fn saturating_add() { + assert_eq!( + u64::max_value(), + Saturating::saturating_add(u64::max_value(), 1) + ) + } + + #[test] + fn saturatiung_sub() { + assert_eq!( + u64::min_value(), + Saturating::saturating_sub(u64::min_value(), 1) + ) + } + + #[test] + fn saturating_mul() { + assert_eq!( + u64::max_value(), + Saturating::saturating_mul(u64::max_value(), 2) + ); + assert_eq!( + i64::min_value(), + Saturating::saturating_mul(i64::min_value(), 2) + ); + assert_eq!( + i64::min_value(), + Saturating::saturating_mul(2, i64::min_value()) + ); + } + + #[test] + fn saturating_pow() { + assert_eq!( + u64::max_value(), + Saturating::saturating_pow(u64::max_value(), 2) + ); + assert_eq!( + i64::max_value(), + Saturating::saturating_pow(i64::min_value(), 2) + ); + assert_eq!( + i64::min_value(), + Saturating::saturating_pow(i64::min_value(), 3) + ); + } +} diff --git a/core/src/env/mod.rs b/core/src/env/mod.rs index 98000466d99..2b448c740b6 100644 --- a/core/src/env/mod.rs +++ b/core/src/env/mod.rs @@ -18,6 +18,7 @@ //! with the outside world through its sandbox boundaries. mod api; +mod arithmetic; mod backend; pub mod call; mod engine; diff --git a/core/src/env/types.rs b/core/src/env/types.rs index ef3ab15de43..3828a3223da 100644 --- a/core/src/env/types.rs +++ b/core/src/env/types.rs @@ -14,33 +14,30 @@ //! Types for the default environment. //! -//! These are simple mirrored types from the default SRML configuration. +//! These are simple mirrored types from the default substrate FRAME configuration. //! Their interfaces and functionality might not be complete. //! //! Users are required to provide their own type definitions and `EnvTypes` //! implementations in order to write ink! contracts for other chain configurations. +//! +//! # Note +//! +//! When authoring a contract, the concrete `EnvTypes` are available via aliases +//! generated by the `lang` macro. Therefore all functionality of the concrete +//! types is accessible in the contract, not constrained by the required trait +//! bounds. +//! +//! Outside of the contract and its tests (e.g. in the offchain environment), where +//! there is no knowledge of the concrete types, the functionality is restricted to +//! the trait bounds on the `EnvTypes` trait types. +use super::arithmetic::AtLeast32BitUnsigned; use core::{ array::TryFromSliceError, convert::TryFrom, - ops::{ - Add, - AddAssign, - Div, - DivAssign, - Mul, - MulAssign, - Sub, - SubAssign, - }, }; use derive_more::From; use ink_prelude::vec::Vec; -use num_traits::{ - Bounded, - One, - Zero, -}; use scale::{ Decode, Encode, @@ -48,82 +45,6 @@ use scale::{ #[cfg(feature = "std")] use scale_info::TypeInfo; -/// Types that allow for simple arithmetic operations. -/// -/// Subset of all trait bounds copied over from what Substrate defines -/// for its `SimpleArithmetic` types. We can extend this in the future -/// if needed. -pub trait SimpleArithmetic: - Sized - + From - + Bounded - + Ord - + PartialOrd - + Zero - + One - + Bounded - + Add - + AddAssign - + Sub - + SubAssign - + Mul - + MulAssign - + Div - + DivAssign -// Further trait bounds from the original SimpleArithmetic trait -// that we could use to extend ink!'s SimpleArithmetic trait. -// -// From + -// From + -// From + -// TryFrom + -// TryFrom + -// TryFrom + -// TryInto + -// TryInto + -// TryInto + -// TryInto + -// TryInto + -// TryInto + -// UniqueSaturatedInto + -// UniqueSaturatedInto + -// UniqueSaturatedInto + -// UniqueSaturatedInto + -// UniqueSaturatedInto + -// UniqueSaturatedFrom + -// UniqueSaturatedFrom + -// Shl + -// Shr + -// CheckedAdd + -// CheckedSub + -// CheckedMul + -// CheckedDiv + -// CheckedShl + -// CheckedShr + -// IntegerSquareRoot + -// Saturating + -{ -} - -impl SimpleArithmetic for T where - T: Sized - + From - + Bounded - + Ord - + PartialOrd - + Zero - + One - + Add - + AddAssign - + Sub - + SubAssign - + Mul - + MulAssign - + Div - + DivAssign -{ -} - /// The environmental types usable by contracts defined with ink!. pub trait EnvTypes { /// The type of an address. @@ -135,7 +56,7 @@ pub trait EnvTypes { + Clone + PartialEq + Eq - + SimpleArithmetic; + + AtLeast32BitUnsigned; /// The type of hash. type Hash: 'static + scale::Codec @@ -154,7 +75,7 @@ pub trait EnvTypes { + Clone + PartialEq + Eq - + SimpleArithmetic; + + AtLeast32BitUnsigned; /// The type of block number. type BlockNumber: 'static + scale::Codec @@ -162,7 +83,7 @@ pub trait EnvTypes { + Clone + PartialEq + Eq - + SimpleArithmetic; + + AtLeast32BitUnsigned; /// The type of a call into the runtime type Call: 'static + scale::Codec; }