Skip to content

[Feat]: No accountId → username resolution/subscription on Asset Hub - app still depends on People Chain, which full usernames never reach #243

Description

@foxwoosh

Component

Proof of Personhood

Priority

P1

Summary

Full usernames registered after the migration exist only on Asset Hub / dotNS, but the mobile app can only resolve usernames by accountId (and subscribe to changes) via People Chain — which full usernames never reach.

Username management is migrating from People Chain (pallet_resources, written by the Identity Backend during attest) to dotNS on Asset Hub. The two flows now behave differently:

  • Lite username (claim): the app calls the Identity Backend, which dual-writes — attest on People Chain and pallet_dotns_gateway::reserve_name on Asset Hub. Lite usernames therefore exist on both chains.
  • Full username (registration/claim as full person): the app submits pallet_dotns_gateway::register_name directly on Asset Hub (V5 general transaction, AsDotnsGateway extension). The Identity Backend is not involved, and nothing writes the full username to People Chain.

The app's only practical way to resolve usernames by accountId — and to subscribe to changes — is still People Chain:

  • Resources::Consumers[accountId] is a single storage read keyed by the account, returning ConsumerInfo { liteUsername, fullUsername, identifierKey (chat ECDH key) }, and it works with standard substrate storage subscriptions (no polling).
  • The app uses it for: own username status (with on-chain subscription), resolving contacts by accountId, chat identity (the ECDH identifierKey), incoming chat requests, backup/recovery of the username after reinstall or on a new device.

On the Asset Hub side there is no equivalent API:

  • pallet_dotns_gateway storage offers only:
    • LiteLabelOwner: label → owner — the wrong direction for accountId lookup;
    • AccountAlias: accountId → alias — proves that the account has an alias (we use it as a "has full username" flag via subscription), but does not contain the username itself.
  • The dotNS contract can answer reverse lookups only via a chain of 5–6 sequential view calls (controller → protocolRegistry() → get("storeFactory") → getLabelStore(h160) → getLabels(), plus pendingClaim(s) for the cold path — reference implementation: resolve_labels in paritytech/host-rust-core#426). These are one-shot eth_call-style reads: not subscribable through substrate storage subscriptions, so the app would have to poll.
  • Contract events (NameRegistered, BaseNameClaimed, LiteNameReserved, … in IDotnsPopController.sol, indexed by user + labelhash) would allow eth_getLogs polling, but that is still polling; eth_subscribe is only available from stable2606.

Consequences:

  1. Full usernames are invisible to other users. Contacts are resolved via People Chain, where a post-migration full username never lands. A full person is shown to peers by their lite (or stale legacy) name.
  2. The user's own full username string cannot be read back from chain. The app currently merges: PC ConsumerInfo (name strings) + AH AccountAlias existence flag + a locally stored full-name string. On reinstall or a second device, recovery reads People Chain only — the full username is unrecoverable; the account degrades to its lite name.
  3. Chat identity depends on PC. The ECDH chat key is read from PC ConsumerInfo, even though dotNS also stores it in the registry.
  4. Circular dependency on the "temporary" dual-write. The spec says PC data duplication is temporary, "solely for backwards compatibility till the app is upgraded". But the app cannot be upgraded off People Chain until Asset Hub offers resolve-by-accountId (ideally subscribable); and People Chain writes cannot be decommissioned until the app migrates. If the backend stops the PC dual-write before this lands, username resolution and recovery break entirely.

Proposal

A queryable — and ideally subscribableaccountId → username(s) source on Asset Hub. Options, from our perspective:

  1. Pallet-level storage map in pallet_dotns_gateway (accountId → lite/full labels, or at least the full label). This is the best fit for mobile: one storage key per account, works with existing substrate storage subscriptions, no polling.
  2. [Feat]: Make gateway names permanent and queryable by address #216 / [Feat]: Add a read-only account-profile lens #217 (names permanent & queryable by address, profileOf(address) — lite/full names, chat key, link, tier in a single view call). This solves the query side in one call, but contract views are still not subscribable, so the app would need eth_getLogs/interval polling on top. Workable, strictly worse than (1) for battery/network.

Concrete questions:

Related: #214 (gateway cleanup umbrella), #215, #216 (names queryable by address), #217 (profileOf(address)); paritytech/host-rust-core#426 — the reference host is making the same PC → AH dotNS resolution move, so resolve-by-address is needed beyond mobile.

App-side dependency points (Android): RealUsernamesOfAccountUseCase (own status: PC ConsumerInfo + AH AccountAlias flag + local string), RealResolveUsernamesUseCase (contacts via PC resolveConsumers), RealRecoverUsernameUseCase (recovery via PC only), UsernameOnChainUpdater (PC storage subscription), AccountAliasUpdater (AH AccountAlias subscription — flag only), chats (SyncContactUsernameUseCase, IncomingChatRequestProcessor, StartChatDataUseCase), backup (BackupFoundInteractor).

Acceptance criteria

  • Given an accountId (or its h160), the app can obtain the account's lite and full usernames from Asset Hub without People Chain involvement.
  • Username changes for an account are observable without client-side interval polling (substrate storage subscription), or a documented polling contract (eth_getLogs on gateway events) is confirmed as the intended mechanism.
  • The chat ECDH key is obtainable from Asset Hub/dotNS by accountId as part of the same lookup.
  • A stated support window for the People Chain dual-write that the app team can plan releases against.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions