Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
232 changes: 232 additions & 0 deletions core/src/env/arithmetic.rs
Original file line number Diff line number Diff line change
@@ -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<u32>
+ Bounded
+ Ord
+ PartialOrd<Self>
+ Zero
+ One
+ Bounded
+ Add<Self, Output = Self>
+ AddAssign<Self>
+ Sub<Self, Output = Self>
+ SubAssign<Self>
+ Mul<Self, Output = Self>
+ MulAssign<Self>
+ Div<Self, Output = Self>
+ DivAssign<Self>
+ CheckedMul
+ Saturating
// Further trait bounds from the original BaseArithmetic trait
// that we could use to extend ink!'s BaseArithmetic trait.
//
// From<u8> +
// From<u16> +
// From<u32> +
// TryFrom<u64> +
// TryFrom<u128> +
// TryFrom<usize> +
// TryInto<u8> +
// TryInto<u16> +
// TryInto<u32> +
// TryInto<u64> +
// TryInto<u128> +
// TryInto<usize> +
// UniqueSaturatedInto<u8> +
// UniqueSaturatedInto<u16> +
// UniqueSaturatedInto<u32> +
// UniqueSaturatedInto<u64> +
// UniqueSaturatedInto<u128> +
// UniqueSaturatedFrom<u64> +
// UniqueSaturatedFrom<u128> +
// Shl<u32, Output = Self> +
// Shr<u32, Output = Self> +
// CheckedAdd +
// CheckedSub +
// CheckedDiv +
// CheckedShl +
// CheckedShr +
// IntegerSquareRoot +
{
}

impl<T> BaseArithmetic for T where
T: Sized
+ From<u32>
+ Bounded
+ Ord
+ PartialOrd<Self>
+ Zero
+ One
+ Add<Self, Output = Self>
+ AddAssign<Self>
+ Sub<Self, Output = Self>
+ SubAssign<Self>
+ Mul<Self, Output = Self>
+ MulAssign<Self>
+ Div<Self, Output = Self>
+ DivAssign<Self>
+ 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<u32>`
/// and smaller integers. All other conversions are fallible.
pub trait AtLeast32Bit: BaseArithmetic + From<u16> + From<u32> {}

impl<T> AtLeast32Bit for T where T: BaseArithmetic + From<u16> + From<u32> {}

/// A meta trait for arithmetic. Same as [`AtLeast32Bit `], but also bounded to be unsigned.
pub trait AtLeast32BitUnsigned: AtLeast32Bit + Unsigned {}

impl<T> 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<T> Saturating for T
where
T: Clone + Zero + One + PartialOrd + CheckedMul + Bounded + num_traits::Saturating,
{
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(|| {
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)
);
}
}
1 change: 1 addition & 0 deletions core/src/env/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
//! with the outside world through its sandbox boundaries.

mod api;
mod arithmetic;
mod backend;
pub mod call;
mod engine;
Expand Down
98 changes: 4 additions & 94 deletions core/src/env/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,110 +20,20 @@
//! Users are required to provide their own type definitions and `EnvTypes`
//! implementations in order to write ink! contracts for other chain configurations.

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,
};
#[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<u32>
+ Bounded
+ Ord
+ PartialOrd<Self>
+ Zero
+ One
+ Bounded
+ Add<Self, Output = Self>
+ AddAssign<Self>
+ Sub<Self, Output = Self>
+ SubAssign<Self>
+ Mul<Self, Output = Self>
+ MulAssign<Self>
+ Div<Self, Output = Self>
+ DivAssign<Self>
// Further trait bounds from the original SimpleArithmetic trait
// that we could use to extend ink!'s SimpleArithmetic trait.
//
// From<u8> +
// From<u16> +
// From<u32> +
// TryFrom<u64> +
// TryFrom<u128> +
// TryFrom<usize> +
// TryInto<u8> +
// TryInto<u16> +
// TryInto<u32> +
// TryInto<u64> +
// TryInto<u128> +
// TryInto<usize> +
// UniqueSaturatedInto<u8> +
// UniqueSaturatedInto<u16> +
// UniqueSaturatedInto<u32> +
// UniqueSaturatedInto<u64> +
// UniqueSaturatedInto<u128> +
// UniqueSaturatedFrom<u64> +
// UniqueSaturatedFrom<u128> +
// Shl<u32, Output = Self> +
// Shr<u32, Output = Self> +
// CheckedAdd +
// CheckedSub +
// CheckedMul +
// CheckedDiv +
// CheckedShl +
// CheckedShr +
// IntegerSquareRoot +
// Saturating +
{
}

impl<T> SimpleArithmetic for T where
T: Sized
+ From<u32>
+ Bounded
+ Ord
+ PartialOrd<Self>
+ Zero
+ One
+ Add<Self, Output = Self>
+ AddAssign<Self>
+ Sub<Self, Output = Self>
+ SubAssign<Self>
+ Mul<Self, Output = Self>
+ MulAssign<Self>
+ Div<Self, Output = Self>
+ DivAssign<Self>
{
}

/// The environmental types usable by contracts defined with ink!.
pub trait EnvTypes {
/// The type of an address.
Expand All @@ -135,7 +45,7 @@ pub trait EnvTypes {
+ Clone
+ PartialEq
+ Eq
+ SimpleArithmetic;
+ AtLeast32BitUnsigned;
/// The type of hash.
type Hash: 'static
+ scale::Codec
Expand All @@ -154,15 +64,15 @@ pub trait EnvTypes {
+ Clone
+ PartialEq
+ Eq
+ SimpleArithmetic;
+ AtLeast32BitUnsigned;
/// The type of block number.
type BlockNumber: 'static
+ scale::Codec
+ Copy
+ Clone
+ PartialEq
+ Eq
+ SimpleArithmetic;
+ AtLeast32BitUnsigned;
/// The type of a call into the runtime
type Call: 'static + scale::Codec;
}
Expand Down