-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Asset Pallet: Support repeated destroys to safely destroy large assets #12310
Changes from 1 commit
6a9d9d1
7db1fd5
cbe14b2
001eaef
1beae07
c9ce171
3067e38
7c4f610
aca497f
634345a
93d886d
2d3b650
5a612d1
b961255
91e3c18
60f954a
ce00b5b
5492b6d
bc20a6c
6ceb592
2edac52
aa2aecf
10fdd90
139d2e9
597f532
a09e762
70930ac
dc4a243
05d778d
62d4f13
e9e108b
5df4a62
544ac52
9206acf
29c7745
2986f29
6ac84a1
1f2930f
791aa7f
450a698
3daef79
ea34cf5
84cbb47
082a10c
e84d5ae
78cde15
c6470fb
85e50b9
c97e850
df27e0b
ca9fa2e
9609f13
26d27cc
72ec8f8
ee30cf8
87a7877
773212e
a4be57f
111da0e
9c06bb8
4eef069
486814f
c185cb0
91095af
9ef3c2b
6165576
7811b62
cd3e28d
aee596e
30814df
9b653a5
57fe747
7ba1ef5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
…hooks
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -665,6 +665,119 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> { | |
| Ok(()) | ||
| } | ||
|
|
||
| /// Start the process of destroying an asset, by setting the asset status to Destroying, and | ||
| /// emitting the DestructionStarted event. | ||
| pub(super) fn do_start_destroy( | ||
| id: T::AssetId, | ||
| maybe_check_owner: Option<T::AccountId>, | ||
| ) -> DispatchResult { | ||
| let _ = | ||
| Asset::<T, I>::try_mutate_exists(id, |maybe_details| -> Result<(), DispatchError> { | ||
| let mut details = maybe_details.as_mut().ok_or(Error::<T, I>::Unknown)?; | ||
| if let Some(check_owner) = maybe_check_owner { | ||
| ensure!(details.owner == check_owner, Error::<T, I>::NoPermission); | ||
| } | ||
| ensure!(details.is_frozen, Error::<T, I>::NotFrozen); | ||
|
||
| details.status = AssetStatus::Destroying; | ||
|
||
|
|
||
| Self::deposit_event(Event::DestructionStarted { asset_id: id }); | ||
| Ok(()) | ||
| })?; | ||
tonyalaribe marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| Ok(()) | ||
| } | ||
|
|
||
| /// Destroy accounts associated with a given asset up to the max (T::RemoveKeysLimit). | ||
| /// | ||
| /// Each call emits the `Event::DestroyedAccountss` event. | ||
tonyalaribe marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| pub(super) fn do_destroy_accounts(id: T::AssetId) -> Result<u32, DispatchError> { | ||
| let mut dead_accounts: Vec<T::AccountId> = vec![]; | ||
| let mut removed_accounts = 0; | ||
tonyalaribe marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| let _ = | ||
ggwpez marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| Asset::<T, I>::try_mutate_exists(id, |maybe_details| -> Result<(), DispatchError> { | ||
| let mut details = maybe_details.as_mut().ok_or(Error::<T, I>::Unknown)?; | ||
| ensure!(details.is_frozen, Error::<T, I>::NotFrozen); | ||
| // Should only destroy accounts while the asset is being destroyed | ||
| ensure!(details.status == AssetStatus::Destroying, Error::<T, I>::LiveAsset); | ||
|
||
|
|
||
| for (who, v) in Account::<T, I>::drain_prefix(id) { | ||
| let _ = Self::dead_account(&who, &mut details, &v.reason, true); | ||
| dead_accounts.push(who); | ||
| removed_accounts = removed_accounts.saturating_add(1); | ||
| if removed_accounts >= T::RemoveKeysLimit::get() { | ||
| break | ||
| } | ||
| } | ||
|
|
||
| Self::deposit_event(Event::DestroyedAccounts { | ||
| asset_id: id, | ||
| accounts_destroyed: removed_accounts as u32, | ||
| accounts_remaining: details.accounts as u32, | ||
| }); | ||
|
||
|
|
||
| Ok(()) | ||
| })?; | ||
|
|
||
| for who in dead_accounts { | ||
| T::Freezer::died(id, &who); | ||
| } | ||
| Ok(removed_accounts) | ||
| } | ||
|
|
||
| /// Destroy approvals associated with a given asset up to the max (T::RemoveKeysLimit). | ||
| /// | ||
| /// Each call emits the `Event::DestroyedApprovals` event | ||
tonyalaribe marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| pub(super) fn do_destroy_approvals(id: T::AssetId) -> Result<u32, DispatchError> { | ||
| let mut removed_approvals = 0; | ||
| let _ = | ||
| Asset::<T, I>::try_mutate_exists(id, |maybe_details| -> Result<(), DispatchError> { | ||
| let mut details = maybe_details.as_mut().ok_or(Error::<T, I>::Unknown)?; | ||
|
|
||
| ensure!(details.is_frozen, Error::<T, I>::NotFrozen); | ||
| // Should only destroy accounts while the asset is being destroyed | ||
| ensure!(details.status == AssetStatus::Destroying, Error::<T, I>::LiveAsset); | ||
|
|
||
| for ((owner, _), approval) in Approvals::<T, I>::drain_prefix((id,)) { | ||
| T::Currency::unreserve(&owner, approval.deposit); | ||
| removed_approvals = removed_approvals.saturating_add(1); | ||
| details.approvals = details.approvals.saturating_sub(1); | ||
| if removed_approvals >= T::RemoveKeysLimit::get() { | ||
| break | ||
| } | ||
| } | ||
| Self::deposit_event(Event::DestroyedApprovals { | ||
| asset_id: id, | ||
| approvals_destroyed: removed_approvals as u32, | ||
| approvals_remaining: details.approvals as u32, | ||
| }); | ||
| Ok(()) | ||
| })?; | ||
| Ok(removed_approvals) | ||
| } | ||
|
|
||
| /// Complete destrouing asset and unreserve the currency. | ||
tonyalaribe marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| /// | ||
| /// On success, the `Event::Destroyed` event is emitted. | ||
| pub(super) fn do_finish_destroy(id: T::AssetId) -> DispatchResult { | ||
| let _ = | ||
| Asset::<T, I>::try_mutate_exists(id, |maybe_details| -> Result<(), DispatchError> { | ||
| let details = maybe_details.take().ok_or(Error::<T, I>::Unknown)?; | ||
| ensure!(details.is_frozen, Error::<T, I>::NotFrozen); | ||
| ensure!(details.status == AssetStatus::Destroying, Error::<T, I>::LiveAsset); | ||
| ensure!(details.accounts == 0, Error::<T, I>::InUse); | ||
|
||
| ensure!(details.approvals == 0, Error::<T, I>::InUse); | ||
|
|
||
| let metadata = Metadata::<T, I>::take(&id); | ||
| T::Currency::unreserve( | ||
| &details.owner, | ||
| details.deposit.saturating_add(metadata.deposit), | ||
| ); | ||
| Self::deposit_event(Event::Destroyed { asset_id: id }); | ||
|
|
||
| Ok(()) | ||
| })?; | ||
| Ok(()) | ||
tonyalaribe marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| /// Creates an approval from `owner` to spend `amount` of asset `id` tokens by 'delegate' | ||
| /// while reserving `T::ApprovalDeposit` from owner | ||
| /// | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.