-
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
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -157,7 +157,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> { | |
| if details.supply.checked_sub(&amount).is_none() { | ||
| return Underflow | ||
| } | ||
| if details.is_frozen { | ||
| if details.status == AssetStatus::Frozen { | ||
| return Frozen | ||
| } | ||
| if amount.is_zero() { | ||
|
|
@@ -205,8 +205,8 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> { | |
| keep_alive: bool, | ||
| ) -> Result<T::Balance, DispatchError> { | ||
| let details = Asset::<T, I>::get(id).ok_or(Error::<T, I>::Unknown)?; | ||
| ensure!(details.status == AssetStatus::Live, Error::<T, I>::AssetNotLive); | ||
| ensure!(!details.is_frozen, Error::<T, I>::Frozen); | ||
| ensure!(details.status != AssetStatus::Destroying, Error::<T, I>::AssetNotLive); | ||
| ensure!(details.status != AssetStatus::Frozen, Error::<T, I>::Frozen); | ||
|
|
||
| let account = Account::<T, I>::get(id, who).ok_or(Error::<T, I>::NoAccount)?; | ||
| ensure!(!account.is_frozen, Error::<T, I>::Frozen); | ||
|
|
@@ -325,7 +325,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> { | |
| let mut details = Asset::<T, I>::get(&id).ok_or(Error::<T, I>::Unknown)?; | ||
|
|
||
| ensure!(account.balance.is_zero() || allow_burn, Error::<T, I>::WouldBurn); | ||
| ensure!(!details.is_frozen, Error::<T, I>::Frozen); | ||
| ensure!(details.status != AssetStatus::Frozen, Error::<T, I>::Frozen); | ||
| ensure!(!account.is_frozen, Error::<T, I>::Frozen); | ||
|
|
||
| T::Currency::unreserve(&who, deposit); | ||
|
|
@@ -392,7 +392,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> { | |
| Self::can_increase(id, beneficiary, amount, true).into_result()?; | ||
| Asset::<T, I>::try_mutate(id, |maybe_details| -> DispatchResult { | ||
| let details = maybe_details.as_mut().ok_or(Error::<T, I>::Unknown)?; | ||
| ensure!(details.status == AssetStatus::Live, Error::<T, I>::AssetNotLive); | ||
| ensure!(details.status != AssetStatus::Destroying, Error::<T, I>::AssetNotLive); | ||
| check(details)?; | ||
|
|
||
| Account::<T, I>::try_mutate(id, beneficiary, |maybe_account| -> DispatchResult { | ||
|
|
@@ -433,7 +433,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> { | |
| f: DebitFlags, | ||
| ) -> Result<T::Balance, DispatchError> { | ||
| let details = Asset::<T, I>::get(id).ok_or(Error::<T, I>::Unknown)?; | ||
| ensure!(details.status == AssetStatus::Live, Error::<T, I>::AssetNotLive); | ||
| ensure!(details.status != AssetStatus::Destroying, Error::<T, I>::AssetNotLive); | ||
|
|
||
| let actual = Self::decrease_balance(id, target, amount, f, |actual, details| { | ||
| // Check admin rights. | ||
|
|
@@ -660,7 +660,6 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> { | |
| accounts: 0, | ||
| sufficients: 0, | ||
| approvals: 0, | ||
| is_frozen: false, | ||
| status: AssetStatus::Live, | ||
| }, | ||
| ); | ||
|
|
@@ -679,7 +678,6 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> { | |
| 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 }); | ||
|
|
@@ -700,8 +698,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> { | |
| 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 | ||
| // Should only destroy accounts while the asset is in a destroying state | ||
| ensure!(details.status == AssetStatus::Destroying, Error::<T, I>::LiveAsset); | ||
|
||
|
|
||
| for (who, v) in Account::<T, I>::drain_prefix(id) { | ||
|
|
@@ -740,8 +737,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> { | |
| 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 | ||
| // Should only destroy accounts while the asset is in a destroying state. | ||
| ensure!(details.status == AssetStatus::Destroying, Error::<T, I>::LiveAsset); | ||
|
|
||
| for ((owner, _), approval) in Approvals::<T, I>::drain_prefix((id,)) { | ||
|
|
@@ -768,7 +764,6 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> { | |
| pub(super) fn do_finish_destroy(id: T::AssetId) -> DispatchResult { | ||
| 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); | ||
|
|
@@ -795,8 +790,8 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> { | |
| amount: T::Balance, | ||
| ) -> DispatchResult { | ||
| let mut d = Asset::<T, I>::get(id).ok_or(Error::<T, I>::Unknown)?; | ||
| ensure!(d.status == AssetStatus::Live, Error::<T, I>::AssetNotLive); | ||
| ensure!(!d.is_frozen, Error::<T, I>::Frozen); | ||
| ensure!(d.status != AssetStatus::Destroying, Error::<T, I>::AssetNotLive); | ||
| ensure!(d.status != AssetStatus::Frozen, Error::<T, I>::Frozen); | ||
| Approvals::<T, I>::try_mutate( | ||
| (id, &owner, &delegate), | ||
| |maybe_approved| -> DispatchResult { | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -346,7 +346,6 @@ pub mod pallet { | |||
| accounts: 0, | ||||
| sufficients: 0, | ||||
| approvals: 0, | ||||
| is_frozen: false, | ||||
| status: AssetStatus::Live, | ||||
| }, | ||||
| ); | ||||
|
|
@@ -562,7 +561,6 @@ pub mod pallet { | |||
| accounts: 0, | ||||
| sufficients: 0, | ||||
| approvals: 0, | ||||
| is_frozen: false, | ||||
| status: AssetStatus::Live, | ||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. wonder if this will require a transaction to set status for all existing Assets?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you mean if we need a migration for existing assets?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, this would need a migration
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @tonyalaribe yes, from what I see, we will need to set Live status to the existing Assets. I also wonder now the purpose of substrate/frame/assets/src/lib.rs Line 992 in 10fdd90
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I imagine we don't want to rely on is_frozen, because anyone could just thaw the asset and unfreeze it. Whereas when you start destroying an asset, there's no going back
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. from my understanding, the
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just scrolled down a bit this PR and noticed there already is an |
||||
| }, | ||||
| ); | ||||
|
|
@@ -925,7 +923,7 @@ pub mod pallet { | |||
| let d = maybe_details.as_mut().ok_or(Error::<T, I>::Unknown)?; | ||||
| ensure!(origin == d.freezer, Error::<T, I>::NoPermission); | ||||
|
|
||||
| d.is_frozen = true; | ||||
| d.status = AssetStatus::Frozen; | ||||
|
|
||||
| Self::deposit_event(Event::<T, I>::AssetFrozen { asset_id: id }); | ||||
| Ok(()) | ||||
|
|
@@ -951,8 +949,9 @@ pub mod pallet { | |||
| Asset::<T, I>::try_mutate(id, |maybe_details| { | ||||
| let d = maybe_details.as_mut().ok_or(Error::<T, I>::Unknown)?; | ||||
| ensure!(origin == d.admin, Error::<T, I>::NoPermission); | ||||
| ensure!(d.status != AssetStatus::Destroying, Error::<T, I>::AssetNotLive); | ||||
|
|
||||
| d.is_frozen = false; | ||||
| d.status = AssetStatus::Live; | ||||
|
|
||||
| Self::deposit_event(Event::<T, I>::AssetThawed { asset_id: id }); | ||||
| Ok(()) | ||||
|
|
@@ -1211,14 +1210,18 @@ pub mod pallet { | |||
|
|
||||
| Asset::<T, I>::try_mutate(id, |maybe_asset| { | ||||
| let mut asset = maybe_asset.take().ok_or(Error::<T, I>::Unknown)?; | ||||
| ensure!(asset.status == AssetStatus::Live, Error::<T, I>::AssetNotLive); | ||||
| ensure!(asset.status != AssetStatus::Destroying, Error::<T, I>::AssetNotLive); | ||||
| asset.owner = T::Lookup::lookup(owner)?; | ||||
| asset.issuer = T::Lookup::lookup(issuer)?; | ||||
| asset.admin = T::Lookup::lookup(admin)?; | ||||
| asset.freezer = T::Lookup::lookup(freezer)?; | ||||
| asset.min_balance = min_balance; | ||||
| asset.is_sufficient = is_sufficient; | ||||
| asset.is_frozen = is_frozen; | ||||
| if is_frozen { | ||||
| asset.status = AssetStatus::Frozen; | ||||
| } else { | ||||
| asset.status = AssetStatus::Live; | ||||
| } | ||||
| *maybe_asset = Some(asset); | ||||
|
|
||||
| Self::deposit_event(Event::AssetStatusChanged { asset_id: id }); | ||||
|
|
||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not just details.status == AssetStatus::Live ?
If someone introduces
TempFrozenfor example, this might be an issue.there are few other cases like this below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because it's dangerous if in future someone adds another status that this function should work for. When that happens, the person would have to remember to update all the extrinsics again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's true, it skipped me. i've pushed an update