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