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:
Alexander Theißen
2021-01-04 13:35:57 +01:00
committed by GitHub
parent f0b99dd2f2
commit 3ba8fdfc11
9 changed files with 1348 additions and 525 deletions
+16 -13
View File
@@ -268,12 +268,12 @@ where
Err(Error::<T>::MaxCallDepthReached)?
}
// Assumption: `collect` doesn't collide with overlay because
// `collect` will be done on first call and destination contract and balance
// cannot be changed before the first call
// We do not allow 'calling' plain accounts. For transfering value
// `seal_transfer` must be used.
let contract = if let Some(ContractInfo::Alive(info)) = Rent::<T>::collect(&dest) {
// This charges the rent and denies access to a contract that is in need of
// eviction by returning `None`. We cannot evict eagerly here because those
// changes would be rolled back in case this contract is called by another
// contract.
// See: https://github.com/paritytech/substrate/issues/6439#issuecomment-648754324
let contract = if let Ok(Some(ContractInfo::Alive(info))) = Rent::<T>::charge(&dest) {
info
} else {
Err(Error::<T>::NotCallable)?
@@ -575,13 +575,16 @@ where
value,
self.ctx,
)?;
let self_trie_id = self.ctx.self_trie_id.as_ref().expect(
"this function is only invoked by in the context of a contract;\
a contract has a trie id;\
this can't be None; qed",
);
Storage::<T>::destroy_contract(&self_id, self_trie_id);
Ok(())
if let Some(ContractInfo::Alive(info)) = ContractInfoOf::<T>::take(&self_id) {
Storage::<T>::queue_trie_for_deletion(&info)?;
Ok(())
} else {
panic!(
"this function is only invoked by in the context of a contract;\
this contract is therefore alive;\
qed"
);
}
}
fn call(