Skip to content

Person's usernames: read from Asset Hub dotNS instead of the People Chain (rebase of #349) - #426

Open
filip-parity wants to merge 12 commits into
mainfrom
filip/349-rebase
Open

Person's usernames: read from Asset Hub dotNS instead of the People Chain (rebase of #349)#426
filip-parity wants to merge 12 commits into
mainfrom
filip/349-rebase

Conversation

@filip-parity

@filip-parity filip-parity commented Aug 17, 2026

Copy link
Copy Markdown

TL;DR

Rebase of #349 ("Person's usernames - read from AH dotNS instead of PC", by @Zebedeusz — kept as the first commit) onto main, with the review fixes on top. Tracks #397; the client half of paritytech/individuality#755 and paritytech/dotns#230.


What the host does after this PR

Usernames come from the dotNS contracts on Asset Hub, not the People Chain. host_logic::dotns_gateway holds the resolution steps once, over a two-method transport (storage, view = ReviveApi_call dry-run from the always-mapped VIEW_CALL_ORIGIN); the CLI drives it over plain RPC (dotns_read.rs) and the in-core runtime over one chainHead_v1 follow opened with runtime (runtime/identity.rs). Every session-identity site (pairing_host.rs, sso_pairing.rs) resolves against the Asset Hub genesis; host_logic/identity.rs (People-chain Resources.Consumers) is gone.

Resolution: DotnsGateway.DispatcherAddressRootGatewayDispatcher.TARGET()DotnsPopControllerpendingClaims(user) (gateway-minted names not yet settled by claimLabelStore) merged with the user's LabelStore labels via protocolRegistry()get(storeFactory)getLabelStore(user) → paged getLabels. Store labels carry the network TLD (protocolRegistry.tld(), .paseo on paseo-next-v2); it is stripped and subnames are dropped. classify_labels re-dots flat lite labels (alice01alice.01, per StringUtils.isSingleDotLiteLabel) and treats the rest as full names. HOST_CLI_DOTNS_POP_CONTROLLER overrides discovery when needed.

register-name (CLI) registers a full-person username through DotnsGateway.register_name: reads the People-collection ring index, members and root revision at one pinned People block, waits for Asset Hub's members-subscriber to hold that revision, then submits a General (v5) extrinsic authorized by AsDotnsGateway = RegisterFullName { proof, ring_index, revision, signature } (shape asserted from metadata before signing) with RestrictOrigins(true); Link::LiteUsername (default: the account's own lite name from dotNS) or Link::None(chat_key). Labels are validated with the pallet's rules ([a-z]+, ≤32 bytes; lite stem.NN) up front.

Configuration: every host config carries the Asset Hub genesis — PairingHostConfig/SigningHostConfig, NativeRuntimeConfig/NativeHostRuntimeConfig (uniffi, Swift/Kotlin wrappers), wasm runtimeConfig.assetHub.genesisHash (required), JS types. Presets: paseo-next-v2 and previewnet (own People/Bulletin/Asset Hub and identity backend), documented in SPEC §14.1 and pinned by the genesis-table test; HOST_CLI_IDENTITY_BACKEND_BASE/_TOKEN override the backend. statement_allowance ring/root helpers take a collection identifier (LitePeople wrappers unchanged; PGAS and allowance paths untouched).


Verified

  • CI-equivalent locally: cargo build/test --workspace --all-features (812 tests), wasm32 check, fmt, clippy -D warnings, iOS bindings --check, codegen no drift.
  • Live, previewnet: auto-managed onboarding (host reservation signature → identity backend 202 → name visible through dotNS/Asset Hub → ring onboarding → paired); identity-check resolves it; pairing-host ⇄ signing-host SSO with getUserId resolved in-core from Asset Hub.
  • Live, paseo-next-v2: identity-check cold path; ignored live tests for the RegisterFullName shape and for a settled store (TLD stripped, ~90 labels paged); the ignored preset-genesis test passes for all six roles.
  • Reservation message, Link, proof message, DOTNS_GATEWAY_CONTEXT, RegisterFullName and the label rules match pallets/dotns-gateway on paritytech/individuality main; contract selectors and ABI shapes match paritytech/dotns master.

Review pointers

The commits after the first one are the review fixes, each with its rationale in the message: in-core follow with runtime (plus a scripted chainHead test), TLD/pending-claim/paging handling, RegisterFullName.revision + refreshed V16 fixture, previewnet Bulletin, docs.


Known, outside this PR

  • The paseo-next-v2 identity backend answers POST /usernames with "dotNS gateway is not enabled in this environment", so accounts registered through it cannot get a dotNS-readable username; the CLI says so and points at previewnet.
  • hosts/dotli must send runtimeConfig.assetHub.genesisHash (required by the wasm host config) — companion change in dotli-community.
  • claimLabelStore is user-signed from the user's own funded H160 and stays outside the host; pending claims expire after 7 days (dotns side).
  • No mainnet preset until the deploy (dotns#223).

Zebedeusz and others added 8 commits August 17, 2026 11:28
…eo-assethub address

The documented 0x1c858C… value predates the Paseo Asset Hub Next V2 reset;
the live DotnsPopController is 0xCC9323… (paritytech/dotns DEPLOYMENTS.md,
same drift as paritytech/dotns#221). Discovery is on-chain, so this only
touches the env-override docs.
…inst the live gateway

Review findings on #349 after the rebase, verified against the live
paseo-next-v2 and previewnet Asset Hubs (spec 2000036, identical) and the
dotNS contracts on master.

In-core identity lookup
- Open the identity follow withRuntime=true. chainHead_v1_call is refused on
  a follow opened without runtime, so every ReviveApi_call view failed and no
  in-core session ever resolved a username; only the CLI's plain-RPC path
  worked. Adds a scripted chainHead test that fails on the old value.
- LabelStore labels carry the network TLD (DotnsPopController._writeRecord
  appends protocolRegistry.tld(); ".paseo" on paseo-next-v2), and the
  classifier only stripped ".dot", so a settled "alice01.paseo" became the
  full username "alice01.paseo". resolve_labels now reads tld(), strips it,
  and drops subnames; classify_labels takes bare labels.
- Always merge pendingClaims with the store: a public registration or an
  incoming transfer deploys the store while gateway names stay pending, so
  the store alone hid them. Page the store (append-only ledger shared with
  public names) instead of reading only the first 16 labels.
- Probe TARGET() and pendingClaims first; target()/pendingClaim are the
  legacy fallbacks (the deployed dispatcher and controller only have the
  former). checked_add on chain-supplied ABI lengths.
- Lite stems follow StringUtils.isSingleDotLiteLabel (DNS label + two
  digits), not alphabetic-only.

register-name
- AsDotnsGatewayInfo::RegisterFullName is {proof, ring_index, revision,
  signature} on the live runtime (individuality#1013); the shape assertion
  and the extra encoding lacked revision, so the command failed at the
  metadata check. Read the People-collection root revision at the pinned
  block, wait for Asset Hub's members-subscriber to import it, and encode
  it. Ring/root/roots helpers take the collection identifier; the LitePeople
  wrappers keep their behaviour.
- Refresh the Asset Hub metadata fixture to the live V16 (spec 2000036).
- Fail early when the member key is onboarded but not yet built into a root
  (the sliced members read cannot prove it), and validate the label and
  --link-lite shape before signing.
…sets

- Previewnet has a live Bulletin chain (wss://previewnet.substrate.dev/bulletin,
  genesis 0x2778b1c9…, "Bulletin Local"), which dotli and dotns-sdk already
  use; the preset borrowed paseo's, so the host advertised and routed a
  Bulletin genesis that disagreed with the app's config.
- The live drift test accepts "Individuality" for the People role
  (previewnet's People chain calls itself "Individuality Local"); it now
  passes for all six roles.
- SPEC.md: previewnet endpoint table (pinned by the genesis-table test for
  every preset), register-name section, env/override wording; README:
  register-name, previewnet, HOST_CLI_* env vars.
- Doc comments still describing usernames as People-chain
  Resources.Consumers reads now name the dotNS contracts on Asset Hub
  (regenerated Swift bindings and codegen golden follow).
…warm-path reads

Ignored network tests against paseo-next-v2 Asset Hub: the live
AsDotnsGatewayInfo::RegisterFullName shape (4 fields) the host asserts before
signing, and the full dotNS resolution chain (pallet storage → dispatcher
TARGET() → controller → registry → store factory → LabelStore) for an
account with a settled store, proving the TLD is stripped and paging covers
the store. Same rationale as the PGAS live tests: a fixture is a snapshot.
is_person_label in paritytech/individuality (support/src/labels.rs) accepts
lowercase ASCII letters only, no digits or hyphens; the register-name
pre-check now enforces the same instead of a looser DNS-label rule.
The paseo-next-v2 identity backend answers POST /usernames with
"dotNS gateway is not enabled in this environment" (verified live), and
since usernames are now read only from dotNS on Asset Hub, accounts
registered through such a backend can never resolve one. Say so, and point
at the previewnet preset / HOST_CLI_IDENTITY_BACKEND_BASE.
…already minted

Review on #349 (re-gius) and paritytech/dotns#235: the gateway enqueues a
reservation for a reserved_base_label without asking the registrar, so a
reservation over a registered name can never be claimed and holds the whole
stem's reservation queue for the reservation window. The contract-side guard
lands in dotns; the client asks first so an attestation cannot fail as a
whole (and lose the lite name) once that guard exists.

label_available reads DotnsRegistrar.available(uint256(node)) for the label's
node under the network tldNode(), through the same transport as the username
reads. attest() checks the reserved base name (shape per the pallet's
is_valid_person, then availability); register-name checks its label. Live
test on paseo: a minted name reports unavailable, an unminted one available.
…tNS registries

Previewnet's DotnsProtocolRegistry predates the configurable TLD (dotns
b4096968) and has no tld()/tldNode(); its TLD is ".dot". Username reads
of a settled LabelStore and the registrar availability check therefore
reverted there. network_tld() reads tld() and falls back to ".dot" when the
view reverts; the TLD node is derived locally (namehash) instead of read.
Live: settled-store labels and available() resolve on both paseo-next-v2
(".paseo") and previewnet (".dot"). The live tests take LIVE_ASSET_HUB_WS,
LIVE_MINTED_LABEL and LIVE_TLD to point at another network.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants