Repository: paritytech/substrate
File: frame/assets/src/functions.rs (Rust)

Code before:
	/// Returns the number of destroyed accounts.
	pub(super) fn do_destroy_accounts(
		id: T::AssetId,
		max_items: u32,
	) -> Result<u32, DispatchError> {
		let mut dead_accounts: Vec<T::AccountId> = vec![];
		let mut remaining_accounts = 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)?;
				// Should only destroy accounts while the asset is in a destroying state
				ensure!(details.status == AssetStatus::Destroying, Error::<T, I>::IncorrectStatus);
				for (i, (who, mut v)) in Account::<T, I>::iter_prefix(&id).enumerate() {
					// unreserve the existence deposit if any
					if let Some((depositor, deposit)) = v.reason.take_deposit_from() {
						T::Currency::unreserve(&depositor, deposit);
					} else if let Some(deposit) = v.reason.take_deposit() {
						T::Currency::unreserve(&who, deposit);
					}
					if let Remove = Self::dead_account(&who, &mut details, &v.reason, false) {
						Account::<T, I>::remove(&id, &who);
						dead_accounts.push(who);
					} else {
						// deposit may have been released, need to update `Account`
						Account::<T, I>::insert(&id, &who, v);
						debug_assert!(false, "destroy did not result in dead account?!");
					}
					if i + 1 >= (max_items as usize) {
						break
					}
				}
				remaining_accounts = details.accounts;
				Ok(())
			})?;

		for who in &dead_accounts {
			T::Freezer::died(id.clone(), &who);
		}

		Self::deposit_event(Event::AccountsDestroyed {
			asset_id: id,
			accounts_destroyed: dead_accounts.len() as u32,
			accounts_remaining: remaining_accounts as u32,
		});
		Ok(dead_accounts.len() as u32)
	}

	/// Destroy approvals associated with a given asset up to the max (T::RemoveItemsLimit).
	///
	/// Each call emits the `Event::DestroyedApprovals` event
	/// Returns the number of destroyed approvals.

Review comment (suggestion):
```suggestion
						defensive!("destroy did not result in dead account?!");
```

Code after:
	/// Returns the number of destroyed accounts.
	pub(super) fn do_destroy_accounts(
		id: T::AssetId,
		max_items: u32,
	) -> Result<u32, DispatchError> {
		let mut dead_accounts: Vec<T::AccountId> = vec![];
		let mut remaining_accounts = 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)?;
				// Should only destroy accounts while the asset is in a destroying state
				ensure!(details.status == AssetStatus::Destroying, Error::<T, I>::IncorrectStatus);
				for (i, (who, mut v)) in Account::<T, I>::iter_prefix(&id).enumerate() {
					// unreserve the existence deposit if any
					if let Some((depositor, deposit)) = v.reason.take_deposit_from() {
						T::Currency::unreserve(&depositor, deposit);
					} else if let Some(deposit) = v.reason.take_deposit() {
						T::Currency::unreserve(&who, deposit);
					}
					if let Remove = Self::dead_account(&who, &mut details, &v.reason, false) {
						Account::<T, I>::remove(&id, &who);
						dead_accounts.push(who);
					} else {
						// deposit may have been released, need to update `Account`
						Account::<T, I>::insert(&id, &who, v);
						defensive!("destroy did not result in dead account?!");
					}
					if i + 1 >= (max_items as usize) {
						break
					}
				}
				remaining_accounts = details.accounts;
				Ok(())
			})?;

		for who in &dead_accounts {
			T::Freezer::died(id.clone(), &who);
		}

		Self::deposit_event(Event::AccountsDestroyed {
			asset_id: id,
			accounts_destroyed: dead_accounts.len() as u32,
			accounts_remaining: remaining_accounts as u32,
		});
		Ok(dead_accounts.len() as u32)
	}

	/// Destroy approvals associated with a given asset up to the max (T::RemoveItemsLimit).
	///
	/// Each call emits the `Event::DestroyedApprovals` event
	/// Returns the number of destroyed approvals.