Make automatic storage deposits resistant against changing deposit prices (#12083)

* Require `FixedPointOperand` for Balances

* Delay deposit calculation

* Make refunds pro rata of consumed storage

* Add storage migration

* Fix clippy

* Add liquidity checks

* Fixe delayed deposit limit enforcement

* Defer charges

* Import Vec

* Add try-runtime hooks for migration

* Fix warning

* Adapt to new OnRuntimeUpgrade trait

* Apply suggestions from code review

Co-authored-by: Sasha Gryaznov <hi@agryaznov.com>

* fmt

* Apply suggestions from code review

Co-authored-by: Sasha Gryaznov <hi@agryaznov.com>

* More suggestions from code review

Co-authored-by: Sasha Gryaznov <hi@agryaznov.com>
This commit is contained in:
Alexander Theißen
2022-09-21 19:31:22 +02:00
committed by GitHub
parent cb82064cb8
commit 857c3bf37b
12 changed files with 957 additions and 312 deletions
+39 -12
View File
@@ -34,31 +34,51 @@ use scale_info::TypeInfo;
use sp_core::crypto::UncheckedFrom;
use sp_io::KillStorageResult;
use sp_runtime::{
traits::{Hash, Zero},
traits::{Hash, Saturating, Zero},
RuntimeDebug,
};
use sp_std::{marker::PhantomData, prelude::*};
pub type ContractInfo<T> = RawContractInfo<CodeHash<T>, BalanceOf<T>>;
/// Information for managing an account and its sub trie abstraction.
/// This is the required info to cache for an account.
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
pub struct RawContractInfo<CodeHash, Balance> {
#[scale_info(skip_type_params(T))]
pub struct ContractInfo<T: Config> {
/// Unique ID for the subtree encoded as a bytes vector.
pub trie_id: TrieId,
/// The code associated with a given account.
pub code_hash: CodeHash,
/// The amount of balance that is currently deposited to pay for consumed storage.
pub storage_deposit: Balance,
pub code_hash: CodeHash<T>,
/// How many bytes of storage are accumulated in this contract's child trie.
pub storage_bytes: u32,
/// How many items of storage are accumulated in this contract's child trie.
pub storage_items: u32,
/// This records to how much deposit the accumulated `storage_bytes` amount to.
pub storage_byte_deposit: BalanceOf<T>,
/// This records to how much deposit the accumulated `storage_items` amount to.
pub storage_item_deposit: BalanceOf<T>,
/// This records how much deposit is put down in order to pay for the contract itself.
///
/// We need to store this information separately so it is not used when calculating any refunds
/// since the base deposit can only ever be refunded on contract termination.
pub storage_base_deposit: BalanceOf<T>,
}
impl<CodeHash, Balance> RawContractInfo<CodeHash, Balance> {
impl<T: Config> ContractInfo<T> {
/// Associated child trie unique id is built from the hash part of the trie id.
#[cfg(test)]
pub fn child_trie_info(&self) -> ChildInfo {
child_trie_info(&self.trie_id[..])
}
/// The deposit paying for the accumulated storage generated within the contract's child trie.
pub fn extra_deposit(&self) -> BalanceOf<T> {
self.storage_byte_deposit.saturating_add(self.storage_item_deposit)
}
/// Same as [`Self::extra_deposit`] but including the base deposit.
pub fn total_deposit(&self) -> BalanceOf<T> {
self.extra_deposit().saturating_add(self.storage_base_deposit)
}
}
/// Associated child trie unique id is built from the hash part of the trie id.
@@ -178,7 +198,7 @@ where
},
(None, None) => (),
}
storage_meter.charge(&diff)?;
storage_meter.charge(&diff);
}
match &new_value {
@@ -200,14 +220,21 @@ where
pub fn new_contract(
account: &AccountIdOf<T>,
trie_id: TrieId,
ch: CodeHash<T>,
code_hash: CodeHash<T>,
) -> Result<ContractInfo<T>, DispatchError> {
if <ContractInfoOf<T>>::contains_key(account) {
return Err(Error::<T>::DuplicateContract.into())
}
let contract =
ContractInfo::<T> { code_hash: ch, trie_id, storage_deposit: <BalanceOf<T>>::zero() };
let contract = ContractInfo::<T> {
code_hash,
trie_id,
storage_bytes: 0,
storage_items: 0,
storage_byte_deposit: Zero::zero(),
storage_item_deposit: Zero::zero(),
storage_base_deposit: Zero::zero(),
};
Ok(contract)
}