Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
6 changes: 3 additions & 3 deletions core/src/env/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,17 +60,17 @@ where
})
}

/// Returns the current price for gas.
/// Returns the price for the specified amount of gas.
///
/// # Errors
///
/// If the returned value cannot be properly decoded.
pub fn gas_price<T>() -> Result<T::Balance>
pub fn gas_price<T>(gas: u64) -> Result<T::Balance>
where
T: EnvTypes,
{
<EnvInstance as OnInstance>::on_instance(|instance| {
TypedEnv::gas_price::<T>(instance)
TypedEnv::gas_price::<T>(instance, gas)
})
}

Expand Down
60 changes: 37 additions & 23 deletions core/src/env/arithmetic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,21 @@

//! Primitive traits for runtime arithmetic, copied from substrate

use core::ops::{
Add,
AddAssign,
Div,
DivAssign,
Mul,
MulAssign,
Sub,
SubAssign,
use core::{
convert::{
TryFrom,
TryInto,
},
ops::{
Add,
AddAssign,
Div,
DivAssign,
Mul,
MulAssign,
Sub,
SubAssign,
},
};
use num_traits::{
checked_pow,
Expand All @@ -40,7 +46,7 @@ use num_traits::{
/// if needed.
pub trait BaseArithmetic:
Sized
+ From<u32>
+ From<u8>
+ Bounded
+ Ord
+ PartialOrd<Self>
Expand All @@ -57,21 +63,19 @@ pub trait BaseArithmetic:
+ DivAssign<Self>
+ CheckedMul
+ Saturating
+ TryFrom<u16>
+ TryFrom<u32>
+ TryFrom<u64>
+ TryFrom<u128>
+ TryFrom<usize>
+ TryInto<u16>
+ TryInto<u32>
+ TryInto<u64>
+ TryInto<u128>
+ TryInto<usize>
// 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> +
Expand All @@ -92,7 +96,7 @@ pub trait BaseArithmetic:

impl<T> BaseArithmetic for T where
T: Sized
+ From<u32>
+ From<u8>
Comment on lines -95 to +99
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain why this change is required for this PR?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this brings it into line with the substrate BaseArithmetic. The From<u32> bound is now defined in the AtLeast32Bit trait, and it is assumed for BaseArtithmetic trait that we are least dealing with u8

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain why this change is required for this PR?

It's not strictly required for this PR, it's just something I overlooked in #463.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah okay so am I right that the above changes actually are aligning ink! further with Substrate traits? Just want to be sure about this because I really am not familiar with the Substrate tests but getting traits righti is really really important.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes exactly.

We are still missing a few more e.g. the rest of the Checked* traits and UniqueSaturatedFrom/ UniqueSaturatedInto, but these are definitely out of scope for this PR.

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())
	}
}

+ Bounded
+ Ord
+ PartialOrd<Self>
Expand All @@ -108,6 +112,16 @@ impl<T> BaseArithmetic for T where
+ DivAssign<Self>
+ CheckedMul
+ Saturating
+ TryFrom<u16>
+ TryFrom<u32>
+ TryFrom<u64>
+ TryFrom<u128>
+ TryFrom<usize>
+ TryInto<u16>
+ TryInto<u32>
+ TryInto<u64>
+ TryInto<u128>
+ TryInto<usize>
Comment on lines +115 to +124
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain why we need this for this PR?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this diverging from what Substrate bounds its types?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain why we need this for this PR?

The TryFrom<u64> is needed to convert the gas: u64 arg into EnvTypes::Balance.

Isn't this diverging from what Substrate bounds its types?

It's converging, I thought I would add the other Try* bounds while I was there: https://github.com/paritytech/substrate/blob/4be954a8463e6f33e0ec854c4b8bcd940af260fc/primitives/arithmetic/src/traits.rs#L44

{
}

Expand Down
4 changes: 2 additions & 2 deletions core/src/env/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,12 +126,12 @@ pub trait TypedEnv: Env {
/// For more details visit: [`ink_core::env::transferred_balance`]
fn transferred_balance<T: EnvTypes>(&mut self) -> Result<T::Balance>;

/// Returns the current price for gas.
/// Returns the price for the specified amount of gas.
///
/// # Note
///
/// For more details visit: [`ink_core::env::gas_price`]
fn gas_price<T: EnvTypes>(&mut self) -> Result<T::Balance>;
fn gas_price<T: EnvTypes>(&mut self, gas: u64) -> Result<T::Balance>;

/// Returns the amount of gas left for the contract execution.
///
Expand Down
8 changes: 8 additions & 0 deletions core/src/env/engine/off_chain/db/chain_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,14 @@ impl ChainSpec {
self.gas_price.decode().map_err(Into::into)
}

/// Set the gas price for the chain.
pub fn set_gas_price<T>(&mut self, gas_price: T::Balance)
where
T: EnvTypes
{
self.gas_price = OffBalance::new(&gas_price)
}

/// Returns the minimum balance for an account on the chain.
pub fn minimum_balance<T>(&self) -> Result<T::Balance>
where
Expand Down
14 changes: 10 additions & 4 deletions core/src/env/engine/off_chain/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ use crate::env::{
TypedEnv,
};
use ink_primitives::Key;
use core::convert::TryInto;
use num_traits::Bounded;

impl EnvInstance {
/// Returns the callee account.
Expand Down Expand Up @@ -153,11 +155,15 @@ impl TypedEnv for EnvInstance {
.map_err(Into::into)
}

fn gas_price<T: EnvTypes>(&mut self) -> Result<T::Balance> {
self.chain_spec
/// Emulates gas price calculation
fn gas_price<T: EnvTypes>(&mut self, gas: u64) -> Result<T::Balance> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be nice to have a test for this function somewhere, since the logic now got more complex and logic surrounding cost analysis should be considered criticial imho. Besides this the code looks sound to me.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it worth adding tests for the offchain environment?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Theoretically yes they are worth. However, the off-chain environment currently lacks tests all over the place because originally it was not intended to stay for long since at the time of writing some standalone Seal implementation was still deemed to be realistic. Consider it a hack that came to stay.

Copy link
Collaborator Author

@ascjones ascjones Jul 2, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a test 👇

use crate::env::arithmetic::Saturating as _;

let gas_price = self.chain_spec
.gas_price::<T>()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be cool if there was an actual conversion config for the off-chain environment so that the returned amount at least scales linearly to the input.

.map_err(|_| scale::Error::from("could not decode gas price"))
.map_err(Into::into)
.map_err(|_| scale::Error::from("could not decode gas price"))?;

Ok(gas_price.saturating_mul(gas.try_into().unwrap_or_else(|_| Bounded::max_value())))
}

fn gas_left<T: EnvTypes>(&mut self) -> Result<T::Balance> {
Expand Down
4 changes: 4 additions & 0 deletions core/src/env/engine/off_chain/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,10 @@ impl EnvInstance {
.last_mut()
.ok_or_else(|| OffChainError::UninitializedBlocks)
}

fn chain_spec_mut(&mut self) -> &mut ChainSpec {
&mut self.chain_spec
}
}

impl OnInstance for EnvInstance {
Expand Down
12 changes: 12 additions & 0 deletions core/src/env/engine/off_chain/test_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use super::{
use crate::env::{
EnvTypes,
Result,
engine::off_chain::db::ChainSpec,
};
use ink_prelude::string::String;

Expand Down Expand Up @@ -210,6 +211,17 @@ where
.map_err(Into::into)
}

/// Update the [ChainSpec](`crate::env::engine::off_chain::db::ChainSpec`) for the test environment
pub fn update_chain_spec<F>(f: F) -> Result<()>
where
F: FnOnce(&mut ChainSpec)
{
<EnvInstance as OnInstance>::on_instance(|instance| {
f(instance.chain_spec_mut())
});
Ok(())
}

/// Returns the contents of the past performed environmental `println` in order.
pub fn recorded_printlns() -> impl Iterator<Item = String> {
<EnvInstance as OnInstance>::on_instance(|instance| {
Expand Down
16 changes: 16 additions & 0 deletions core/src/env/engine/off_chain/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,19 @@ fn key_add_sub() -> Result<()> {
Ok(())
})
}

#[test]
fn gas_price() -> env::Result<()> {
env::test::run_test::<env::DefaultEnvTypes, _>(|_| {
let gas_price= 2u32;
env::test::update_chain_spec(|chain_spec| {
chain_spec.set_gas_price::<env::DefaultEnvTypes>(gas_price.into())
})?;

assert_eq!(2u128, env::gas_price::<env::DefaultEnvTypes>(1).unwrap());
assert_eq!(20u128, env::gas_price::<env::DefaultEnvTypes>(10).unwrap());
assert_eq!(6u128, env::gas_price::<env::DefaultEnvTypes>(3).unwrap());

Ok(())
})
}
7 changes: 5 additions & 2 deletions core/src/env/engine/on_chain/ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ mod sys {
pub fn ext_block_number();
pub fn ext_address();
pub fn ext_balance();
pub fn ext_gas_price();
pub fn ext_gas_price(gas: u64);
pub fn ext_gas_left();
pub fn ext_value_transferred();
pub fn ext_now();
Expand Down Expand Up @@ -285,7 +285,6 @@ impl_ext_wrapper_for! {
(block_number => ext_block_number),
(address => ext_address),
(balance => ext_balance),
(gas_price => ext_gas_price),
(gas_left => ext_gas_left),
(value_transferred => ext_value_transferred),
(now => ext_now),
Expand All @@ -294,6 +293,10 @@ impl_ext_wrapper_for! {
(tombstone_deposit => ext_tombstone_deposit),
}

pub fn gas_price(gas: u64) {
unsafe { sys::ext_gas_price(gas) }
}

pub fn set_rent_allowance(value: &[u8]) {
unsafe { sys::ext_set_rent_allowance(value.as_ptr() as u32, value.len() as u32) }
}
Expand Down
9 changes: 5 additions & 4 deletions core/src/env/engine/on_chain/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,10 +208,6 @@ impl TypedEnv for EnvInstance {
self.get_property::<T::Balance>(ext::value_transferred)
}

fn gas_price<T: EnvTypes>(&mut self) -> Result<T::Balance> {
self.get_property::<T::Balance>(ext::gas_price)
}

fn gas_left<T: EnvTypes>(&mut self) -> Result<T::Balance> {
self.get_property::<T::Balance>(ext::gas_left)
}
Expand Down Expand Up @@ -380,6 +376,11 @@ impl TypedEnv for EnvInstance {
ext::transfer(destination, value)
}

fn gas_price<T: EnvTypes>(&mut self, gas: u64) -> Result<T::Balance> {
ext::gas_price(gas);
self.decode_scratch_buffer().map_err(Into::into)
}

fn random<T>(&mut self, subject: &[u8]) -> Result<T::Hash>
where
T: EnvTypes,
Expand Down
6 changes: 3 additions & 3 deletions lang/src/env_access.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,13 +104,13 @@ where
env::transferred_balance::<T>().expect("couldn't decode transferred balance")
}

/// Returns the current price for gas.
/// Returns the price for the specified amount of gas.
///
/// # Note
///
/// For more details visit: [`ink_core::env::gas_price`]
pub fn gas_price(self) -> T::Balance {
env::gas_price::<T>().expect("couldn't decode gas price")
pub fn gas_price(self, gas: u64) -> T::Balance {
env::gas_price::<T>(gas).expect("couldn't decode gas price")
}

/// Returns the amount of gas left for the contract execution.
Expand Down