3

I know the concept of existential deposit (ED) means that if the account balance is below this value, it will be wiped out. I tried to figure out how it works. The AccountData is defined in the runtime while stored in the frame-system pallet. try_mutate_exists in the frame_system pallet used to mutate AccountData storage, but how and where does the substrate system wipe the account whose balance below ED? I find OnKilledAccount type in the frame_system::Config, but it's more like a callback after the account has been killed.

impl<T: Config> StoredMap<T::AccountId, T::AccountData> for Pallet<T> {
    fn get(k: &T::AccountId) -> T::AccountData {
        Account::<T>::get(k).data
    }

    fn try_mutate_exists<R, E: From<DispatchError>>(
        k: &T::AccountId,
        f: impl FnOnce(&mut Option<T::AccountData>) -> Result<R, E>,
    ) -> Result<R, E> {
        let account = Account::<T>::get(k);
        let was_providing = is_providing(&account.data);
        let mut some_data = if was_providing {
            Some(account.data)
        } else {
            None
        };
        let result = f(&mut some_data)?;
        let is_providing = some_data.is_some();
        if !was_providing && is_providing {
            Self::inc_providers(k);
        } else if was_providing && !is_providing {
            match Self::dec_providers(k)? { // This may trigger account wipe
                DecRefStatus::Reaped => return Ok(result),
                DecRefStatus::Exists => {
                    // Update value as normal...
                }
            }
        } else if !was_providing && !is_providing {
            return Ok(result);
        }
        Account::<T>::mutate(k, |a| a.data = some_data.unwrap_or_default());
        Ok(result)
    }
}
0

1 Answer 1

3

Through the DustCleaner.


Take transfer as an example.

When you call the transfer it will call try_mutate_account_with_dust internally.

Let's go back to the transfer. The closure which pass to the try_mutate_account_with_dust will return a result after the allow_death check.

Then if the result is Ok(()). A DustCleaner instance will be created. Just a Rust tip: if the result is Err(..) then the result.map(..) does nothing.

Finally, when the DustCleaner instance gets dropped somewhere, the Drop will be triggered. Then the account gets killed/recycled.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.