Draft: (paused) Resolve "Use consumers for identities (instead of sufficients) so identities cannot bypass existential deposit"
Changes
- Runtime behavior change for identity accounts created after this update:
- identity lifecycle references now use
consumersinstead ofsufficientson identity creation/removal/key-change paths. - as a result,
Balances::transfer_allcan no longer drain a newly created identity account to zero; the account keeps at leastExistentialDeposit.
- identity lifecycle references now use
- New guardrail on owner key reuse:
- introduced
OldOwnerKeysstorage set (AccountId -> ()) to track keys that have ever been anold_owner_key. -
create_identitynow rejects any receiver key present inOldOwnerKeys(OwnerKeyAlreadyUsed). - this prevents creating a new identity with a previously rotated-out owner key.
- introduced
Migration/compatibility notes:
- Legacy identities (created before this change) may still carry identity refs in
sufficients. - Cleanup now uses a unified rule: decrement
sufficientswhen present, otherwise decrementconsumers. - New identity owner keys must be provider-backed (
providers >= 1) for bothcreate_identityandchange_owner_key. - Genesis compatibility retained:
- genesis identities use
consumerswhen the account has providers, - fallback to
sufficientsfor funding-less/provider-less genesis accounts.
- genesis identities use
-
OldOwnerKeysis also populated from genesis identities that already containold_owner_key.
Goal of the changes
Ensure identity accounts cannot bypass account liveness constraints by relying on sufficients, align identity lifecycle refs with the consumer/provider model expected by balances account reaping semantics, and prevent unsafe owner-key reuse after key rotation.
What reviewers need to know
Identity refcount model update
-
pallets/identity/src/lib.rs-
create_identity:inc_consumersinstead ofinc_sufficients. -
change_owner_key:- enforce provider-backed
new_key, - mark previous owner key in
OldOwnerKeys, - use
inc_consumersfor the new owner key, - cleanup of previous owner refs goes through
dec_identity_ref_count.
- enforce provider-backed
-
do_remove_identity: owner and old-owner cleanup also go throughdec_identity_ref_count. - introduced helper:
-
dec_identity_ref_count(account_id):-
dec_sufficientsifsufficients > 0, - else
dec_consumersifconsumers > 0, - else no-op.
-
-
-
check_create_identity:- receiver must have at least one provider,
- receiver must not be present in
OldOwnerKeys.
-
Owner-key history tracking
-
pallets/identity/src/lib.rs- new storage
OldOwnerKeys. - populated:
- during genesis build for identities with an
old_owner_key, - during owner-key rotation when current owner becomes old owner.
- during genesis build for identities with an
- new storage
Test coverage added/updated
-
runtime/gdev/tests/balance_tests.rs-
test_transfer_all_identity_cannot_drainvalidates a newly created identity account keepsExistentialDepositaftertransfer_all(..., false).
-
-
pallets/identity/src/tests.rs- extended assertions around
consumers/sufficientsin creation/removal/key-change flows. - added focused tests for legacy/new cleanup behavior and repeated key changes.
- added
test_old_owner_key_can_transfer_all_and_reach_zero_counters. - added
test_create_identity_forbidden_with_old_owner_keyfor the newOldOwnerKeysrule.
- extended assertions around
-
pallets/identity/src/mock.rs+pallets/identity/Cargo.toml- added
pallet_balancesin identity test runtime/dev-deps to enable unit-leveltransfer_allcoverage.
- added
Closes #350 (closed)
Edited by Éloïs