Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement seal_rent_params #755

Merged
merged 13 commits into from
May 26, 2021
1 change: 1 addition & 0 deletions crates/env/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ cfg-if = "1.0"
paste = "1.0"
arrayref = "0.3"
static_assertions = "1.1"
sp-arithmetic = { version = "3.0", default-features = false }

# Hashes for the off-chain environment.
sha2 = { version = "0.9", optional = true }
Expand Down
17 changes: 17 additions & 0 deletions crates/env/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ use crate::{
HashOutput,
},
topics::Topics,
types::RentParams,
Environment,
Result,
};
Expand Down Expand Up @@ -155,6 +156,20 @@ where
})
}

/// Returns information needed for rent calculations.
///
/// # Errors
///
/// If the returned value cannot be properly decoded.
pub fn rent_params<T>() -> Result<RentParams<T>>
where
T: Environment,
{
<EnvInstance as OnInstance>::on_instance(|instance| {
TypedEnvBackend::rent_params::<T>(instance)
})
}

/// Returns the current block number.
///
/// # Errors
Expand Down Expand Up @@ -401,6 +416,8 @@ pub fn restore_contract<T>(
/// This removes the calling account and transfers all remaining balance
/// to the given beneficiary.
///
/// No tombstone will be created, this function kills a contract completely!
///
/// # Note
///
/// This function never returns. Either the termination was successful and the
Expand Down
8 changes: 8 additions & 0 deletions crates/env/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use crate::{
HashOutput,
},
topics::Topics,
types::RentParams,
Environment,
Result,
};
Expand Down Expand Up @@ -222,6 +223,13 @@ pub trait TypedEnvBackend: EnvBackend {
/// For more details visit: [`rent_allowance`][`crate::rent_allowance`]
fn rent_allowance<T: Environment>(&mut self) -> Result<T::Balance>;

/// Returns information needed for rent calculations.
///
/// # Note
///
/// For more details visit: [`RentParams`][`crate::RentParams`]
fn rent_params<T: Environment>(&mut self) -> Result<RentParams<T>>;

/// Returns the current block number.
///
/// # Note
Expand Down
8 changes: 8 additions & 0 deletions crates/env/src/engine/experimental_off_chain/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ use crate::{
Clear,
EnvBackend,
Environment,
RentParams,
Result,
ReturnFlags,
TypedEnvBackend,
Expand Down Expand Up @@ -301,6 +302,13 @@ impl TypedEnvBackend for EnvInstance {
self.get_property::<T::Balance>(Engine::rent_allowance)
}

fn rent_params<T>(&mut self) -> Result<RentParams<T>>
where
T: Environment,
{
unimplemented!("off-chain environment does not support rent params")
}

fn block_number<T: Environment>(&mut self) -> Result<T::BlockNumber> {
self.get_property::<T::BlockNumber>(Engine::block_number)
}
Expand Down
68 changes: 67 additions & 1 deletion crates/env/src/engine/off_chain/db/chain_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ use super::{
OffBalance,
OffTimestamp,
};
use crate::Environment;
use crate::{
engine::off_chain::types::OffRentFraction,
Environment,
};
use sp_arithmetic::PerThing;

/// The chain specification.
pub struct ChainSpec {
Expand All @@ -29,6 +33,14 @@ pub struct ChainSpec {
tombstone_deposit: OffBalance,
/// The targeted block time.
block_time: OffTimestamp,
/// The balance a contract needs to deposit per storage byte to stay alive indefinitely.
deposit_per_storage_byte: OffBalance,
/// The balance every contract needs to deposit to stay alive indefinitely.
deposit_per_contract: OffBalance,
/// The balance a contract needs to deposit per storage item to stay alive indefinitely.
deposit_per_storage_item: OffBalance,
/// The fraction of the deposit costs that should be used as rent per block.
rent_fraction: OffRentFraction,
}

impl ChainSpec {
Expand All @@ -39,6 +51,10 @@ impl ChainSpec {
minimum_balance: OffBalance::uninitialized(),
tombstone_deposit: OffBalance::uninitialized(),
block_time: OffTimestamp::uninitialized(),
deposit_per_storage_byte: OffBalance::uninitialized(),
deposit_per_contract: OffBalance::uninitialized(),
deposit_per_storage_item: OffBalance::uninitialized(),
rent_fraction: OffRentFraction::uninitialized(),
}
}

Expand All @@ -48,6 +64,10 @@ impl ChainSpec {
self.minimum_balance = OffBalance::uninitialized();
self.tombstone_deposit = OffBalance::uninitialized();
self.block_time = OffTimestamp::uninitialized();
self.deposit_per_storage_byte = OffBalance::uninitialized();
self.deposit_per_contract = OffBalance::uninitialized();
self.deposit_per_storage_item = OffBalance::uninitialized();
self.rent_fraction = OffRentFraction::uninitialized();
}

/// Default initialization for the off-chain specification.
Expand All @@ -64,6 +84,20 @@ impl ChainSpec {
.try_initialize::<T::Balance>(&T::Balance::from(16u32))?;
self.block_time
.try_initialize::<T::Timestamp>(&T::Timestamp::from(5u32))?;

let deposit_per_storage_byte = 10_000u32;
self.deposit_per_storage_byte
.try_initialize::<T::Balance>(&T::Balance::from(deposit_per_storage_byte))?;
self.deposit_per_contract
.try_initialize::<T::Balance>(&T::Balance::from(
8 * deposit_per_storage_byte,
))?;
self.deposit_per_storage_item
.try_initialize::<T::Balance>(&T::Balance::from(10_000u32))?;
self.rent_fraction.try_initialize::<T::RentFraction>(
&T::RentFraction::from_rational_approximation(4, 10_000),
)?;

Ok(())
}

Expand Down Expand Up @@ -106,4 +140,36 @@ impl ChainSpec {
{
self.block_time.decode().map_err(Into::into)
}

/// The balance a contract needs to deposit per storage byte to stay alive indefinitely.
pub fn deposit_per_storage_byte<T>(&self) -> Result<T::Balance>
where
T: Environment,
{
self.deposit_per_storage_byte.decode().map_err(Into::into)
}

/// The balance every contract needs to deposit to stay alive indefinitely.
pub fn deposit_per_contract<T>(&self) -> Result<T::Balance>
where
T: Environment,
{
self.deposit_per_contract.decode().map_err(Into::into)
}

/// The balance a contract needs to deposit per storage item to stay alive indefinitely.
pub fn deposit_per_storage_item<T>(&self) -> Result<T::Balance>
where
T: Environment,
{
self.deposit_per_storage_item.decode().map_err(Into::into)
}

/// The fraction of the deposit costs that should be used as rent per block.
pub fn rent_fraction<T>(&self) -> Result<T::RentFraction>
where
T: Environment,
{
self.rent_fraction.decode().map_err(Into::into)
}
}
63 changes: 52 additions & 11 deletions crates/env/src/engine/off_chain/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ use crate::{
Sha2x256,
},
topics::Topics,
types::RentParams,
EnvBackend,
Environment,
Error,
Expand All @@ -43,15 +44,15 @@ use core::convert::TryInto;
use ink_primitives::Key;
use num_traits::Bounded;

const UNITIALIZED_EXEC_CONTEXT: &str = "unitialized execution context: \
const UNINITIALIZED_EXEC_CONTEXT: &str = "uninitialized execution context: \
a possible source of error could be that you are using `#[test]` instead of `#[ink::test]`.";

impl EnvInstance {
/// Returns the callee account.
fn callee_account(&self) -> &Account {
let callee = self
.exec_context()
.expect(UNITIALIZED_EXEC_CONTEXT)
.expect(UNINITIALIZED_EXEC_CONTEXT)
.callee
.clone();
self.accounts
Expand All @@ -63,7 +64,7 @@ impl EnvInstance {
fn callee_account_mut(&mut self) -> &mut Account {
let callee = self
.exec_context()
.expect(UNITIALIZED_EXEC_CONTEXT)
.expect(UNINITIALIZED_EXEC_CONTEXT)
.callee
.clone();
self.accounts
Expand Down Expand Up @@ -166,7 +167,7 @@ impl EnvBackend for EnvInstance {
where
R: scale::Encode,
{
let ctx = self.exec_context_mut().expect(UNITIALIZED_EXEC_CONTEXT);
let ctx = self.exec_context_mut().expect(UNINITIALIZED_EXEC_CONTEXT);
ctx.output = Some(return_value.encode());
std::process::exit(flags.into_u32() as i32)
}
Expand Down Expand Up @@ -285,15 +286,15 @@ impl EnvInstance {
impl TypedEnvBackend for EnvInstance {
fn caller<T: Environment>(&mut self) -> Result<T::AccountId> {
self.exec_context()
.expect(UNITIALIZED_EXEC_CONTEXT)
.expect(UNINITIALIZED_EXEC_CONTEXT)
.caller::<T>()
.map_err(|_| scale::Error::from("could not decode caller"))
.map_err(Into::into)
}

fn transferred_balance<T: Environment>(&mut self) -> Result<T::Balance> {
self.exec_context()
.expect(UNITIALIZED_EXEC_CONTEXT)
.expect(UNINITIALIZED_EXEC_CONTEXT)
.transferred_value::<T>()
.map_err(|_| scale::Error::from("could not decode transferred balance"))
.map_err(Into::into)
Expand All @@ -314,23 +315,23 @@ impl TypedEnvBackend for EnvInstance {

fn gas_left<T: Environment>(&mut self) -> Result<T::Balance> {
self.exec_context()
.expect(UNITIALIZED_EXEC_CONTEXT)
.expect(UNINITIALIZED_EXEC_CONTEXT)
.gas::<T>()
.map_err(|_| scale::Error::from("could not decode gas left"))
.map_err(Into::into)
}

fn block_timestamp<T: Environment>(&mut self) -> Result<T::Timestamp> {
self.current_block()
.expect(UNITIALIZED_EXEC_CONTEXT)
.expect(UNINITIALIZED_EXEC_CONTEXT)
.timestamp::<T>()
.map_err(|_| scale::Error::from("could not decode block time"))
.map_err(Into::into)
}

fn account_id<T: Environment>(&mut self) -> Result<T::AccountId> {
self.exec_context()
.expect(UNITIALIZED_EXEC_CONTEXT)
.expect(UNINITIALIZED_EXEC_CONTEXT)
.callee::<T>()
.map_err(|_| scale::Error::from("could not decode callee"))
.map_err(Into::into)
Expand All @@ -350,9 +351,49 @@ impl TypedEnvBackend for EnvInstance {
.map_err(Into::into)
}

fn rent_params<T>(&mut self) -> Result<RentParams<T>>
where
T: Environment,
{
use crate::arithmetic::Saturating as _;

let total_balance = self.balance::<T>()?;

// the off-chain environment does currently not support reserved balance,
// hence we just use the total balance here.
let free_balance = self.balance::<T>()?;

let deposit_per_contract = self.chain_spec.deposit_per_contract::<T>()?;
let deposit_per_storage_byte = self.chain_spec.deposit_per_storage_byte::<T>()?;
let deposit_per_storage_item = self.chain_spec.deposit_per_storage_item::<T>()?;
let rent_fraction = self.chain_spec.rent_fraction::<T>()?;
let minimum_balance: T::Balance = self.minimum_balance::<T>()?;
let tombstone_deposit = self.tombstone_deposit::<T>()?;
let subsistence_threshold = minimum_balance.saturating_add(tombstone_deposit);
let rent_allowance = self.rent_allowance::<T>()?;

Ok(RentParams {
deposit_per_contract,
deposit_per_storage_byte,
deposit_per_storage_item,
rent_fraction,
subsistence_threshold,

rent_allowance,
total_balance,
free_balance,

storage_size: 0,
code_size: 0,
code_refcount: 0,

_reserved: None,
})
}

fn block_number<T: Environment>(&mut self) -> Result<T::BlockNumber> {
self.current_block()
.expect(UNITIALIZED_EXEC_CONTEXT)
.expect(UNINITIALIZED_EXEC_CONTEXT)
.number::<T>()
.map_err(|_| scale::Error::from("could not decode block number"))
.map_err(Into::into)
Expand Down Expand Up @@ -453,7 +494,7 @@ impl TypedEnvBackend for EnvInstance {
where
T: Environment,
{
let block = self.current_block().expect(UNITIALIZED_EXEC_CONTEXT);
let block = self.current_block().expect(UNINITIALIZED_EXEC_CONTEXT);
Ok((block.random::<T>(subject)?, block.number::<T>()?))
}
}
4 changes: 4 additions & 0 deletions crates/env/src/engine/off_chain/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ mod type_marker {
#[derive(Debug, Clone)] pub enum OffTimestamp {}
/// Type marker representing an environmental `BlockNumber`.
#[derive(Debug, Clone)] pub enum BlockNumber {}
/// Type marker representing an environmental `RentFraction`.
#[derive(Debug, Clone)] pub enum RentFraction {}
}

/// Off-chain environment account ID type.
Expand All @@ -52,3 +54,5 @@ pub type OffHash = TypedEncoded<type_marker::Hash>;
pub type OffTimestamp = TypedEncoded<type_marker::OffTimestamp>;
/// Off-chain environment block number type.
pub type OffBlockNumber = TypedEncoded<type_marker::BlockNumber>;
/// Off-chain environment rent fraction type.
pub type OffRentFraction = TypedEncoded<type_marker::RentFraction>;
21 changes: 21 additions & 0 deletions crates/env/src/engine/on_chain/ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,14 @@ mod sys {
output_len_ptr: Ptr32Mut<u32>,
);
}

#[link(wasm_import_module = "__unstable__")]
extern "C" {
pub fn seal_rent_params(
output_ptr: Ptr32Mut<[u8]>,
output_len_ptr: Ptr32Mut<u32>,
);
}
}

fn extract_from_slice(output: &mut &mut [u8], new_len: usize) {
Expand Down Expand Up @@ -589,6 +597,19 @@ pub fn set_rent_allowance(value: &[u8]) {
unsafe { sys::seal_set_rent_allowance(Ptr32::from_slice(value), value.len() as u32) }
}

pub fn rent_params(output: &mut &mut [u8]) {
cmichi marked this conversation as resolved.
Show resolved Hide resolved
let mut output_len = output.len() as u32;
{
unsafe {
sys::seal_rent_params(
Ptr32Mut::from_slice(output),
Ptr32Mut::from_ref(&mut output_len),
)
};
}
extract_from_slice(output, output_len as usize);
}

pub fn random(subject: &[u8], output: &mut &mut [u8]) {
let mut output_len = output.len() as u32;
{
Expand Down
Loading