Add ext_terminate (#5234)

With this patch forward this will be the only way for
a contract to destroy itself. This patch therefore changes
the semantics of all other contract initiated balance
transfers to fail if they would bring the caller below the
existential deposit.
This commit is contained in:
Alexander Theißen
2020-03-17 11:51:34 +01:00
committed by GitHub
parent e91d4be998
commit 601f2538c6
5 changed files with 377 additions and 97 deletions
+73 -1
View File
@@ -182,6 +182,12 @@ mod tests {
gas_left: u64,
}
#[derive(Debug, PartialEq, Eq)]
struct TerminationEntry {
beneficiary: u64,
gas_left: u64,
}
#[derive(Debug, PartialEq, Eq)]
struct TransferEntry {
to: u64,
@@ -195,6 +201,7 @@ mod tests {
storage: HashMap<StorageKey, Vec<u8>>,
rent_allowance: u64,
instantiates: Vec<InstantiateEntry>,
terminations: Vec<TerminationEntry>,
transfers: Vec<TransferEntry>,
dispatches: Vec<DispatchEntry>,
restores: Vec<RestoreEntry>,
@@ -242,7 +249,13 @@ mod tests {
let address = self.next_account_id;
self.next_account_id += 1;
Ok((address, ExecReturnValue { status: STATUS_SUCCESS, data: Vec::new() }))
Ok((
address,
ExecReturnValue {
status: STATUS_SUCCESS,
data: Vec::new(),
},
))
}
fn transfer(
&mut self,
@@ -275,6 +288,17 @@ mod tests {
// TODO: Add tests for different call outcomes.
Ok(ExecReturnValue { status: STATUS_SUCCESS, data: Vec::new() })
}
fn terminate(
&mut self,
beneficiary: &u64,
gas_meter: &mut GasMeter<Test>,
) -> Result<(), DispatchError> {
self.terminations.push(TerminationEntry {
beneficiary: *beneficiary,
gas_left: gas_meter.gas_left(),
});
Ok(())
}
fn note_dispatch_call(&mut self, call: Call) {
self.dispatches.push(DispatchEntry(call));
}
@@ -379,6 +403,13 @@ mod tests {
) -> Result<(), DispatchError> {
(**self).transfer(to, value, gas_meter)
}
fn terminate(
&mut self,
beneficiary: &u64,
gas_meter: &mut GasMeter<Test>,
) -> Result<(), DispatchError> {
(**self).terminate(beneficiary, gas_meter)
}
fn call(
&mut self,
to: &u64,
@@ -649,6 +680,47 @@ mod tests {
);
}
const CODE_TERMINATE: &str = r#"
(module
;; ext_terminate(
;; beneficiary_ptr: u32,
;; beneficiary_len: u32,
;; )
(import "env" "ext_terminate" (func $ext_terminate (param i32 i32)))
(import "env" "memory" (memory 1 1))
(func (export "call")
(call $ext_terminate
(i32.const 4) ;; Pointer to "beneficiary" address.
(i32.const 8) ;; Length of "beneficiary" address.
)
)
(func (export "deploy"))
;; Beneficiary AccountId to transfer the funds.
;; Represented by u64 (8 bytes long) in little endian.
(data (i32.const 4) "\09\00\00\00\00\00\00\00")
)
"#;
#[test]
fn contract_terminate() {
let mut mock_ext = MockExt::default();
execute(
CODE_TERMINATE,
vec![],
&mut mock_ext,
&mut GasMeter::with_limit(50_000, 1),
).unwrap();
assert_eq!(
&mock_ext.terminations,
&[TerminationEntry {
beneficiary: 0x09,
gas_left: 49989,
}]
);
}
const CODE_TRANSFER_LIMITED_GAS: &str = r#"
(module
;; ext_call(