From 389b8f1698f696e880d122b2cf2338441b37d058 Mon Sep 17 00:00:00 2001 From: Hero Bird <robin.freyler@gmail.com> Date: Thu, 23 Jan 2020 15:13:49 +0100 Subject: [PATCH] [contracts] Add ext_tombstone_deposit (#4722) * [contracts] add ext_tombstone_deposit * [contracts] update tombstone_deposit docs --- substrate/frame/contracts/src/exec.rs | 7 ++ substrate/frame/contracts/src/lib.rs | 2 + substrate/frame/contracts/src/wasm/mod.rs | 66 +++++++++++++++++++ substrate/frame/contracts/src/wasm/runtime.rs | 17 +++++ 4 files changed, 92 insertions(+) diff --git a/substrate/frame/contracts/src/exec.rs b/substrate/frame/contracts/src/exec.rs index 9d786c320b5..ceaccd35cb6 100644 --- a/substrate/frame/contracts/src/exec.rs +++ b/substrate/frame/contracts/src/exec.rs @@ -161,6 +161,9 @@ pub trait Ext { /// Returns the minimum balance that is required for creating an account. fn minimum_balance(&self) -> BalanceOf<Self::T>; + /// Returns the deposit required to create a tombstone upon contract eviction. + fn tombstone_deposit(&self) -> BalanceOf<Self::T>; + /// Returns a random number for the current block with the given subject. fn random(&self, subject: &[u8]) -> SeedOf<Self::T>; @@ -779,6 +782,10 @@ where self.ctx.config.existential_deposit } + fn tombstone_deposit(&self) -> BalanceOf<T> { + self.ctx.config.tombstone_deposit + } + fn deposit_event(&mut self, topics: Vec<T::Hash>, data: Vec<u8>) { self.ctx.deferred.push(DeferredAction::DepositEvent { topics, diff --git a/substrate/frame/contracts/src/lib.rs b/substrate/frame/contracts/src/lib.rs index 40ce86518a5..d16462d8bf5 100644 --- a/substrate/frame/contracts/src/lib.rs +++ b/substrate/frame/contracts/src/lib.rs @@ -969,6 +969,7 @@ impl<T: Trait> OnFreeBalanceZero<T::AccountId> for Module<T> { pub struct Config<T: Trait> { pub schedule: Schedule, pub existential_deposit: BalanceOf<T>, + pub tombstone_deposit: BalanceOf<T>, pub max_depth: u32, pub max_value_size: u32, pub contract_account_instantiate_fee: BalanceOf<T>, @@ -981,6 +982,7 @@ impl<T: Trait> Config<T> { Config { schedule: <Module<T>>::current_schedule(), existential_deposit: T::Currency::minimum_balance(), + tombstone_deposit: T::TombstoneDeposit::get(), max_depth: T::MaxDepth::get(), max_value_size: T::MaxValueSize::get(), contract_account_instantiate_fee: T::ContractFee::get(), diff --git a/substrate/frame/contracts/src/wasm/mod.rs b/substrate/frame/contracts/src/wasm/mod.rs index 60402cf3a09..1ea2067a8d2 100644 --- a/substrate/frame/contracts/src/wasm/mod.rs +++ b/substrate/frame/contracts/src/wasm/mod.rs @@ -299,6 +299,10 @@ mod tests { 666 } + fn tombstone_deposit(&self) -> u64 { + 16 + } + fn random(&self, subject: &[u8]) -> H256 { H256::from_slice(subject) } @@ -397,6 +401,9 @@ mod tests { fn minimum_balance(&self) -> u64 { (**self).minimum_balance() } + fn tombstone_deposit(&self) -> u64 { + (**self).tombstone_deposit() + } fn random(&self, subject: &[u8]) -> H256 { (**self).random(subject) } @@ -1271,6 +1278,65 @@ mod tests { ).unwrap(); } + const CODE_TOMBSTONE_DEPOSIT: &str = r#" +(module + (import "env" "ext_tombstone_deposit" (func $ext_tombstone_deposit)) + (import "env" "ext_scratch_size" (func $ext_scratch_size (result i32))) + (import "env" "ext_scratch_read" (func $ext_scratch_read (param i32 i32 i32))) + (import "env" "memory" (memory 1 1)) + + (func $assert (param i32) + (block $ok + (br_if $ok + (get_local 0) + ) + (unreachable) + ) + ) + + (func (export "call") + (call $ext_tombstone_deposit) + + ;; assert $ext_scratch_size == 8 + (call $assert + (i32.eq + (call $ext_scratch_size) + (i32.const 8) + ) + ) + + ;; copy contents of the scratch buffer into the contract's memory. + (call $ext_scratch_read + (i32.const 8) ;; Pointer in memory to the place where to copy. + (i32.const 0) ;; Offset from the start of the scratch buffer. + (i32.const 8) ;; Count of bytes to copy. + ) + + ;; assert that contents of the buffer is equal to the i64 value of 16. + (call $assert + (i64.eq + (i64.load + (i32.const 8) + ) + (i64.const 16) + ) + ) + ) + (func (export "deploy")) +) +"#; + + #[test] + fn tombstone_deposit() { + let mut gas_meter = GasMeter::with_limit(50_000, 1); + let _ = execute( + CODE_TOMBSTONE_DEPOSIT, + vec![], + MockExt::default(), + &mut gas_meter, + ).unwrap(); + } + const CODE_RANDOM: &str = r#" (module (import "env" "ext_random" (func $ext_random (param i32 i32))) diff --git a/substrate/frame/contracts/src/wasm/runtime.rs b/substrate/frame/contracts/src/wasm/runtime.rs index 75751b6d359..07cb8cb524e 100644 --- a/substrate/frame/contracts/src/wasm/runtime.rs +++ b/substrate/frame/contracts/src/wasm/runtime.rs @@ -623,6 +623,23 @@ define_env!(Env, <E: Ext>, Ok(()) }, + // Stores the tombstone deposit into the scratch buffer. + // + // The data is encoded as T::Balance. The current contents of the scratch + // buffer are overwritten. + // + // # Note + // + // The tombstone deposit is on top of the existential deposit. So in order for + // a contract to leave a tombstone the balance of the contract must not go + // below the sum of existential deposit and the tombstone deposit. The sum + // is commonly referred as subsistence threshold in code. + ext_tombstone_deposit(ctx) => { + ctx.scratch_buf.clear(); + ctx.ext.tombstone_deposit().encode_to(&mut ctx.scratch_buf); + Ok(()) + }, + // Decodes the given buffer as a `T::Call` and adds it to the list // of to-be-dispatched calls. // -- GitLab