srml-contracts: Deferred actions (#3255)

* Switch to deferred actions

* Make restore_to a deferred action.

* Bump version.

* Review fixes.
This commit is contained in:
Sergei Pepyakin
2019-08-01 09:52:59 +02:00
committed by Gavin Wood
parent 780942192e
commit de02aee156
6 changed files with 337 additions and 171 deletions
@@ -586,6 +586,87 @@ define_env!(Env, <E: Ext>,
Ok(())
},
// Record a request to restore the caller contract to the specified contract.
//
// At the finalization stage, i.e. when all changes from the extrinsic that invoked this
// contract are commited, this function will compute a tombstone hash from the caller's
// storage and the given code hash and if the hash matches the hash found in the tombstone at
// the specified address - kill the caller contract and restore the destination contract and set
// the specified `rent_allowance`. All caller's funds are transfered to the destination.
//
// This function doesn't perform restoration right away but defers it to the end of the
// transaction. If there is no tombstone in the destination address or if the hashes don't match
// then restoration is cancelled and no changes are made.
//
// `dest_ptr`, `dest_len` - the pointer and the length of a buffer that encodes `T::AccountId`
// with the address of the to be restored contract.
// `code_hash_ptr`, `code_hash_len` - the pointer and the length of a buffer that encodes
// a code hash of the to be restored contract.
// `rent_allowance_ptr`, `rent_allowance_len` - the pointer and the length of a buffer that
// encodes the rent allowance that must be set in the case of successful restoration.
// `delta_ptr` is the pointer to the start of a buffer that has `delta_count` storage keys
// laid out sequentially.
ext_restore_to(
ctx,
dest_ptr: u32,
dest_len: u32,
code_hash_ptr: u32,
code_hash_len: u32,
rent_allowance_ptr: u32,
rent_allowance_len: u32,
delta_ptr: u32,
delta_count: u32
) => {
let dest = {
let dest_buf = read_sandbox_memory(ctx, dest_ptr, dest_len)?;
<<E as Ext>::T as system::Trait>::AccountId::decode(&mut &dest_buf[..])
.ok_or_else(|| sandbox::HostError)?
};
let code_hash = {
let code_hash_buf = read_sandbox_memory(ctx, code_hash_ptr, code_hash_len)?;
<CodeHash<<E as Ext>::T>>::decode(&mut &code_hash_buf[..])
.ok_or_else(|| sandbox::HostError)?
};
let rent_allowance = {
let rent_allowance_buf = read_sandbox_memory(
ctx,
rent_allowance_ptr,
rent_allowance_len
)?;
BalanceOf::<<E as Ext>::T>::decode(&mut &rent_allowance_buf[..])
.ok_or_else(|| sandbox::HostError)?
};
let delta = {
// We don't use `with_capacity` here to not eagerly allocate the user specified amount
// of memory.
let mut delta = Vec::new();
let mut key_ptr = delta_ptr;
for _ in 0..delta_count {
const KEY_SIZE: usize = 32;
// Read the delta into the provided buffer and collect it into the buffer.
let mut delta_key: StorageKey = [0; KEY_SIZE];
read_sandbox_memory_into_buf(ctx, key_ptr, &mut delta_key)?;
delta.push(delta_key);
// Offset key_ptr to the next element.
key_ptr = key_ptr.checked_add(KEY_SIZE as u32).ok_or_else(|| sandbox::HostError)?;
}
delta
};
ctx.ext.note_restore_to(
dest,
code_hash,
rent_allowance,
delta,
);
Ok(())
},
// Returns the size of the scratch buffer.
//
// For more details on the scratch buffer see `ext_scratch_copy`.