mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-07-23 09:35:42 +00:00
pallet-contracts: migrate to nested storage transaction mechanism (#6382)
* Add a simple direct storage access module * WIP * Completely migrate to the transactional system. * Format * Fix wasm compilation * Get rid of account_db module * Make deposit event eager * Make restore_to eager * It almost compiles. * Make it compile. * Make the tests compile * Get rid of account_db * Drop the result. * Backport the book keeping. * Fix all remaining tests. * Make it compile for std * Remove a stale TODO marker * Remove another stale TODO * Add proof for `terminate` * Remove a stale comment. * Make restoration diverging. * Remove redudnant trait: `ComputeDispatchFee` * Update frame/contracts/src/exec.rs Co-authored-by: Alexander Theißen <alex.theissen@me.com> * Introduce proper errors into the storage module. * Adds comments for contract storage module. * Inline `ExecutionContext::terminate`. * Restore_to should not let sacrifice itself if the contract present on the stack. * Inline `transfer` function * Update doc - add "if succeeded" * Adapt to TransactionOutcome changes * Updates the docs for `ext_restore_to` * Add a proper assert. * Update frame/contracts/src/wasm/runtime.rs Co-authored-by: Alexander Theißen <alex.theissen@me.com> Co-authored-by: Alexander Theißen <alex.theissen@me.com> Co-authored-by: Alexander Theißen <alexander.theissen@parity.io>
This commit is contained in:
@@ -18,8 +18,10 @@
|
||||
|
||||
use crate::{
|
||||
AliveContractInfo, BalanceOf, ContractInfo, ContractInfoOf, Module, RawEvent,
|
||||
TombstoneContractInfo, Trait,
|
||||
TombstoneContractInfo, Trait, CodeHash,
|
||||
};
|
||||
use sp_std::prelude::*;
|
||||
use sp_io::hashing::blake2_256;
|
||||
use frame_support::storage::child;
|
||||
use frame_support::traits::{Currency, ExistenceRequirement, Get, OnUnbalanced, WithdrawReason};
|
||||
use frame_support::StorageMap;
|
||||
@@ -396,3 +398,90 @@ pub fn compute_rent_projection<T: Trait>(
|
||||
current_block_number + blocks_left,
|
||||
))
|
||||
}
|
||||
|
||||
/// Restores the destination account using the origin as prototype.
|
||||
///
|
||||
/// The restoration will be performed iff:
|
||||
/// - origin exists and is alive,
|
||||
/// - the origin's storage is not written in the current block
|
||||
/// - the restored account has tombstone
|
||||
/// - the tombstone matches the hash of the origin storage root, and code hash.
|
||||
///
|
||||
/// Upon succesful restoration, `origin` will be destroyed, all its funds are transferred to
|
||||
/// the restored account. The restored account will inherit the last write block and its last
|
||||
/// deduct block will be set to the current block.
|
||||
pub fn restore_to<T: Trait>(
|
||||
origin: T::AccountId,
|
||||
dest: T::AccountId,
|
||||
code_hash: CodeHash<T>,
|
||||
rent_allowance: BalanceOf<T>,
|
||||
delta: Vec<crate::exec::StorageKey>,
|
||||
) -> Result<(), &'static str> {
|
||||
let mut origin_contract = <ContractInfoOf<T>>::get(&origin)
|
||||
.and_then(|c| c.get_alive())
|
||||
.ok_or("Cannot restore from inexisting or tombstone contract")?;
|
||||
|
||||
let child_trie_info = origin_contract.child_trie_info();
|
||||
|
||||
let current_block = <frame_system::Module<T>>::block_number();
|
||||
|
||||
if origin_contract.last_write == Some(current_block) {
|
||||
return Err("Origin TrieId written in the current block");
|
||||
}
|
||||
|
||||
let dest_tombstone = <ContractInfoOf<T>>::get(&dest)
|
||||
.and_then(|c| c.get_tombstone())
|
||||
.ok_or("Cannot restore to inexisting or alive contract")?;
|
||||
|
||||
let last_write = if !delta.is_empty() {
|
||||
Some(current_block)
|
||||
} else {
|
||||
origin_contract.last_write
|
||||
};
|
||||
|
||||
let key_values_taken = delta.iter()
|
||||
.filter_map(|key| {
|
||||
child::get_raw(&child_trie_info, &blake2_256(key)).map(|value| {
|
||||
child::kill(&child_trie_info, &blake2_256(key));
|
||||
(key, value)
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let tombstone = <TombstoneContractInfo<T>>::new(
|
||||
// This operation is cheap enough because last_write (delta not included)
|
||||
// is not this block as it has been checked earlier.
|
||||
&child::root(&child_trie_info)[..],
|
||||
code_hash,
|
||||
);
|
||||
|
||||
if tombstone != dest_tombstone {
|
||||
for (key, value) in key_values_taken {
|
||||
child::put_raw(&child_trie_info, &blake2_256(key), &value);
|
||||
}
|
||||
|
||||
return Err("Tombstones don't match");
|
||||
}
|
||||
|
||||
origin_contract.storage_size -= key_values_taken.iter()
|
||||
.map(|(_, value)| value.len() as u32)
|
||||
.sum::<u32>();
|
||||
|
||||
<ContractInfoOf<T>>::remove(&origin);
|
||||
<ContractInfoOf<T>>::insert(&dest, ContractInfo::Alive(AliveContractInfo::<T> {
|
||||
trie_id: origin_contract.trie_id,
|
||||
storage_size: origin_contract.storage_size,
|
||||
empty_pair_count: origin_contract.empty_pair_count,
|
||||
total_pair_count: origin_contract.total_pair_count,
|
||||
code_hash,
|
||||
rent_allowance,
|
||||
deduct_block: current_block,
|
||||
last_write,
|
||||
}));
|
||||
|
||||
let origin_free_balance = T::Currency::free_balance(&origin);
|
||||
T::Currency::make_free_balance_be(&origin, <BalanceOf<T>>::zero());
|
||||
T::Currency::deposit_creating(&dest, origin_free_balance);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user