mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 04:41:02 +00:00
contracts: Lazy storage removal (#7740)
* Do not evict a contract from within a call stack We don't want to trigger contract eviction automatically when a contract is called. This is because those changes can be reverted due to how storage transactions are used at the moment. More Information: https://github.com/paritytech/substrate/issues/6439#issuecomment-648754324 It can be re-introduced once the linked issue is resolved. In the meantime `claim_surcharge` must be called to evict a contract. * Lazily delete storage in on_initialize instead of when removing the contract * Add missing documentation of new error * Make Module::claim_surcharge public It being the only dispatchable that is private is an oversight. * review: Add final newline * review: Simplify assert statement * Add test that checks that partial remove of a contract works * Premote warning to error * Added missing docs for seal_terminate * Lazy deletion should only take AVERAGE_ON_INITIALIZE_RATIO of the block * Added informational about the lazy deletion throughput * Avoid lazy deletion in case the block is already full * Prevent queue decoding in case of an already full block * Add test that checks that on_initialize honors block limits
This commit is contained in:
committed by
GitHub
parent
f0b99dd2f2
commit
3ba8fdfc11
@@ -123,7 +123,7 @@ use frame_support::{
|
||||
dispatch::{DispatchResult, DispatchResultWithPostInfo},
|
||||
traits::{OnUnbalanced, Currency, Get, Time, Randomness},
|
||||
};
|
||||
use frame_system::{ensure_signed, ensure_root};
|
||||
use frame_system::{ensure_signed, ensure_root, Module as System};
|
||||
use pallet_contracts_primitives::{
|
||||
RentProjectionResult, GetStorageResult, ContractAccessError, ContractExecResult, ExecResult,
|
||||
};
|
||||
@@ -325,6 +325,12 @@ pub trait Config: frame_system::Config {
|
||||
|
||||
/// Type that allows the runtime authors to add new host functions for a contract to call.
|
||||
type ChainExtension: chain_extension::ChainExtension;
|
||||
|
||||
/// The maximum number of tries that can be queued for deletion.
|
||||
type DeletionQueueDepth: Get<u32>;
|
||||
|
||||
/// The maximum amount of weight that can be consumed per block for lazy trie removal.
|
||||
type DeletionWeightLimit: Get<Weight>;
|
||||
}
|
||||
|
||||
decl_error! {
|
||||
@@ -396,6 +402,17 @@ decl_error! {
|
||||
/// in this error. Note that this usually shouldn't happen as deploying such contracts
|
||||
/// is rejected.
|
||||
NoChainExtension,
|
||||
/// Removal of a contract failed because the deletion queue is full.
|
||||
///
|
||||
/// This can happen when either calling [`Module::claim_surcharge`] or `seal_terminate`.
|
||||
/// The queue is filled by deleting contracts and emptied by a fixed amount each block.
|
||||
/// Trying again during another block is the only way to resolve this issue.
|
||||
DeletionQueueFull,
|
||||
/// A contract could not be evicted because it has enough balance to pay rent.
|
||||
///
|
||||
/// This can be returned from [`Module::claim_surcharge`] because the target
|
||||
/// contract has enough balance to pay for its rent.
|
||||
ContractNotEvictable,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -449,8 +466,24 @@ decl_module! {
|
||||
/// The maximum size of a storage value in bytes. A reasonable default is 16 KiB.
|
||||
const MaxValueSize: u32 = T::MaxValueSize::get();
|
||||
|
||||
/// The maximum number of tries that can be queued for deletion.
|
||||
const DeletionQueueDepth: u32 = T::DeletionQueueDepth::get();
|
||||
|
||||
/// The maximum amount of weight that can be consumed per block for lazy trie removal.
|
||||
const DeletionWeightLimit: Weight = T::DeletionWeightLimit::get();
|
||||
|
||||
fn deposit_event() = default;
|
||||
|
||||
fn on_initialize() -> Weight {
|
||||
// We do not want to go above the block limit and rather avoid lazy deletion
|
||||
// in that case. This should only happen on runtime upgrades.
|
||||
let weight_limit = T::BlockWeights::get().max_block
|
||||
.saturating_sub(System::<T>::block_weight().total())
|
||||
.min(T::DeletionWeightLimit::get());
|
||||
Storage::<T>::process_deletion_queue_batch(weight_limit)
|
||||
.saturating_add(T::WeightInfo::on_initialize())
|
||||
}
|
||||
|
||||
/// Updates the schedule for metering contracts.
|
||||
///
|
||||
/// The schedule must have a greater version than the stored schedule.
|
||||
@@ -549,10 +582,14 @@ decl_module! {
|
||||
/// Allows block producers to claim a small reward for evicting a contract. If a block producer
|
||||
/// fails to do so, a regular users will be allowed to claim the reward.
|
||||
///
|
||||
/// If contract is not evicted as a result of this call, no actions are taken and
|
||||
/// the sender is not eligible for the reward.
|
||||
/// If contract is not evicted as a result of this call, [`Error::ContractNotEvictable`]
|
||||
/// is returned and the sender is not eligible for the reward.
|
||||
#[weight = T::WeightInfo::claim_surcharge()]
|
||||
fn claim_surcharge(origin, dest: T::AccountId, aux_sender: Option<T::AccountId>) {
|
||||
pub fn claim_surcharge(
|
||||
origin,
|
||||
dest: T::AccountId,
|
||||
aux_sender: Option<T::AccountId>
|
||||
) -> DispatchResult {
|
||||
let origin = origin.into();
|
||||
let (signed, rewarded) = match (origin, aux_sender) {
|
||||
(Ok(frame_system::RawOrigin::Signed(account)), None) => {
|
||||
@@ -574,8 +611,10 @@ decl_module! {
|
||||
};
|
||||
|
||||
// If poking the contract has lead to eviction of the contract, give out the rewards.
|
||||
if Rent::<T>::snitch_contract_should_be_evicted(&dest, handicap) {
|
||||
T::Currency::deposit_into_existing(&rewarded, T::SurchargeReward::get())?;
|
||||
if Rent::<T>::snitch_contract_should_be_evicted(&dest, handicap)? {
|
||||
T::Currency::deposit_into_existing(&rewarded, T::SurchargeReward::get()).map(|_| ())
|
||||
} else {
|
||||
Err(Error::<T>::ContractNotEvictable.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -733,6 +772,11 @@ decl_storage! {
|
||||
///
|
||||
/// TWOX-NOTE: SAFE since `AccountId` is a secure hash.
|
||||
pub ContractInfoOf: map hasher(twox_64_concat) T::AccountId => Option<ContractInfo<T>>;
|
||||
/// Evicted contracts that await child trie deletion.
|
||||
///
|
||||
/// Child trie deletion is a heavy operation depending on the amount of storage items
|
||||
/// stored in said trie. Therefore this operation is performed lazily in `on_initialize`.
|
||||
pub DeletionQueue: Vec<storage::DeletedContract>;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user