diff --git a/core/src/env/api.rs b/core/src/env/api.rs index 3e1c46f035b..5e0f73c8b21 100644 --- a/core/src/env/api.rs +++ b/core/src/env/api.rs @@ -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() -> Result +pub fn gas_price(gas: u64) -> Result where T: EnvTypes, { ::on_instance(|instance| { - TypedEnv::gas_price::(instance) + TypedEnv::gas_price::(instance, gas) }) } diff --git a/core/src/env/arithmetic.rs b/core/src/env/arithmetic.rs index 14c43b10826..75629af84b6 100644 --- a/core/src/env/arithmetic.rs +++ b/core/src/env/arithmetic.rs @@ -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, @@ -40,7 +46,7 @@ use num_traits::{ /// if needed. pub trait BaseArithmetic: Sized - + From + + From + Bounded + Ord + PartialOrd @@ -57,21 +63,19 @@ pub trait BaseArithmetic: + DivAssign + CheckedMul + Saturating + + TryFrom + + TryFrom + + TryFrom + + TryFrom + + TryFrom + + TryInto + + TryInto + + TryInto + + TryInto + + TryInto // 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 + @@ -92,7 +96,7 @@ pub trait BaseArithmetic: impl BaseArithmetic for T where T: Sized - + From + + From + Bounded + Ord + PartialOrd @@ -108,6 +112,16 @@ impl BaseArithmetic for T where + DivAssign + CheckedMul + Saturating + + TryFrom + + TryFrom + + TryFrom + + TryFrom + + TryFrom + + TryInto + + TryInto + + TryInto + + TryInto + + TryInto { } diff --git a/core/src/env/backend.rs b/core/src/env/backend.rs index a9b11f290ea..54599365528 100644 --- a/core/src/env/backend.rs +++ b/core/src/env/backend.rs @@ -126,12 +126,12 @@ pub trait TypedEnv: Env { /// For more details visit: [`ink_core::env::transferred_balance`] fn transferred_balance(&mut self) -> Result; - /// 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(&mut self) -> Result; + fn gas_price(&mut self, gas: u64) -> Result; /// Returns the amount of gas left for the contract execution. /// diff --git a/core/src/env/engine/off_chain/db/chain_spec.rs b/core/src/env/engine/off_chain/db/chain_spec.rs index aa5315d74c0..731f2f18ea0 100644 --- a/core/src/env/engine/off_chain/db/chain_spec.rs +++ b/core/src/env/engine/off_chain/db/chain_spec.rs @@ -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(&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(&self) -> Result where diff --git a/core/src/env/engine/off_chain/impls.rs b/core/src/env/engine/off_chain/impls.rs index 23af67d2bf4..df41adea4fa 100644 --- a/core/src/env/engine/off_chain/impls.rs +++ b/core/src/env/engine/off_chain/impls.rs @@ -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. @@ -153,11 +155,15 @@ impl TypedEnv for EnvInstance { .map_err(Into::into) } - fn gas_price(&mut self) -> Result { - self.chain_spec + /// Emulates gas price calculation + fn gas_price(&mut self, gas: u64) -> Result { + use crate::env::arithmetic::Saturating as _; + + let gas_price = self.chain_spec .gas_price::() - .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(&mut self) -> Result { diff --git a/core/src/env/engine/off_chain/mod.rs b/core/src/env/engine/off_chain/mod.rs index 7f586220b87..21013eee161 100644 --- a/core/src/env/engine/off_chain/mod.rs +++ b/core/src/env/engine/off_chain/mod.rs @@ -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 { diff --git a/core/src/env/engine/off_chain/test_api.rs b/core/src/env/engine/off_chain/test_api.rs index a8427251e48..73bd3da1687 100644 --- a/core/src/env/engine/off_chain/test_api.rs +++ b/core/src/env/engine/off_chain/test_api.rs @@ -25,6 +25,7 @@ use super::{ use crate::env::{ EnvTypes, Result, + engine::off_chain::db::ChainSpec, }; use ink_prelude::string::String; @@ -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) -> Result<()> +where + F: FnOnce(&mut ChainSpec) +{ + ::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 { ::on_instance(|instance| { diff --git a/core/src/env/engine/off_chain/tests.rs b/core/src/env/engine/off_chain/tests.rs index 48b2c39d508..f3979b24592 100644 --- a/core/src/env/engine/off_chain/tests.rs +++ b/core/src/env/engine/off_chain/tests.rs @@ -68,3 +68,19 @@ fn key_add_sub() -> Result<()> { Ok(()) }) } + +#[test] +fn gas_price() -> env::Result<()> { + env::test::run_test::(|_| { + let gas_price= 2u32; + env::test::update_chain_spec(|chain_spec| { + chain_spec.set_gas_price::(gas_price.into()) + })?; + + assert_eq!(2u128, env::gas_price::(1).unwrap()); + assert_eq!(20u128, env::gas_price::(10).unwrap()); + assert_eq!(6u128, env::gas_price::(3).unwrap()); + + Ok(()) + }) +} diff --git a/core/src/env/engine/on_chain/ext.rs b/core/src/env/engine/on_chain/ext.rs index 72f308bc869..98a27d84f6c 100644 --- a/core/src/env/engine/on_chain/ext.rs +++ b/core/src/env/engine/on_chain/ext.rs @@ -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(); @@ -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), @@ -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) } } diff --git a/core/src/env/engine/on_chain/impls.rs b/core/src/env/engine/on_chain/impls.rs index 40c8768385c..ea09bec3275 100644 --- a/core/src/env/engine/on_chain/impls.rs +++ b/core/src/env/engine/on_chain/impls.rs @@ -208,10 +208,6 @@ impl TypedEnv for EnvInstance { self.get_property::(ext::value_transferred) } - fn gas_price(&mut self) -> Result { - self.get_property::(ext::gas_price) - } - fn gas_left(&mut self) -> Result { self.get_property::(ext::gas_left) } @@ -380,6 +376,11 @@ impl TypedEnv for EnvInstance { ext::transfer(destination, value) } + fn gas_price(&mut self, gas: u64) -> Result { + ext::gas_price(gas); + self.decode_scratch_buffer().map_err(Into::into) + } + fn random(&mut self, subject: &[u8]) -> Result where T: EnvTypes, diff --git a/lang/src/env_access.rs b/lang/src/env_access.rs index 68600fc3c41..2e9793d46c0 100644 --- a/lang/src/env_access.rs +++ b/lang/src/env_access.rs @@ -104,13 +104,13 @@ where env::transferred_balance::().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::().expect("couldn't decode gas price") + pub fn gas_price(self, gas: u64) -> T::Balance { + env::gas_price::(gas).expect("couldn't decode gas price") } /// Returns the amount of gas left for the contract execution.