Skip to content

extend SMP protocol to support name availability queries by labelhash - #1863

Open
brenzi wants to merge 59 commits into
masterfrom
ab/snrc-resolver-SMP-NAVL
Open

extend SMP protocol to support name availability queries by labelhash#1863
brenzi wants to merge 59 commits into
masterfrom
ab/snrc-resolver-SMP-NAVL

Conversation

@brenzi

@brenzi brenzi commented Sep 5, 2026

Copy link
Copy Markdown
Collaborator

Let users query name availability by labelhash (without revealing plaintext name unless it resolves)
They should get a precise answer with details in all possible cases (expired, grace, auction, reserved)

  • bump SMP protocol version to 22
    • make sure to roll out snrc resolver (which is reverse-compatible) before upgrading any production SMP relay to v22. otherwise .testing names will stop resolving for everybody using v22 relays

e2e test against

Comment thread src/Simplex/Messaging/Server/Names.hs Outdated
Comment thread src/Simplex/Messaging/Server/Names.hs Outdated
Comment thread src/Simplex/Messaging/Protocol.hs Outdated
Comment thread src/Simplex/Messaging/Protocol.hs Outdated
Comment thread src/Simplex/Messaging/Protocol.hs Outdated
Comment thread src/Simplex/Messaging/Protocol.hs Outdated
Comment thread src/Simplex/Messaging/Protocol.hs Outdated
Comment thread src/Simplex/Messaging/Protocol.hs Outdated
Comment thread src/Simplex/Messaging/Protocol.hs Outdated
Comment thread src/Simplex/Messaging/SimplexName.hs Outdated
@brenzi
brenzi removed this pull request from stack #1862 September 10, 2026 11:29
@brenzi
brenzi changed the base branch from ab/snrc-resolver-expiry-and-availability to master September 10, 2026 11:29
@brenzi brenzi changed the title extend SMP protocol to support name availability queries extend SMP protocol to support name availability queries by labelhash Sep 10, 2026
  sumTypeJSON switches to the _owsf form on swift builds, but this JSON is
  the RNAME payload and the resolver's HTTP contract, so a swift client and
  a Linux relay would disagree on every field. taggedObjectJSON is what it
  already resolves to everywhere else.

  The label modifier keeps the reservedReason_ collision escape out of the
  API, as AgentWorkersDetails does: both arms now say reservedReason.
  httpGet read the response body before checking the status, so an oversized
  error page surfaced as a transient "response too large" instead of the
  authoritative status. Reverting it to its previous shape restores that and
  removes the status test both callers had been re-deriving.

  registration() had no tests at all, though it is the endpoint SMP v22
  consumes. RegistrationV2Tests covers the three answer shapes, the error
  paths and the exact key set of each, which is the wire contract.

  auctionUntil was always None with no consumer. The spec claimed a reason
  word travels unchanged; a resolver can only send a word it has, and SNRC's
  registry records a number.
  /v2/resolve answers 200, 400 or 502, and an unregistered name is
  NRAvailable, so no status means "not registered". Mapping 400/404/410 to
  NOT_FOUND made a misconfigured relay deny every name, and hid a relay
  upgraded ahead of its resolver. All three now surface as RESOLVER.

  rslvNotFound would have gone dead, so it counts what its name says: an
  availability answer the encoder downgrades for a session below v22. The
  wire is unchanged.

  A hashed query the registrar cannot name is refused with 502 rather than
  answered with a record named "unknown", which the client rejects anyway.
  NRRUnknown is capped to 32 printable characters again, as the spec says.
  A registered name that is also reserved no longer offers a date it will
  never free up on. rentPrices is registrationPrices throughout, and
  yearPriceUSD is USDCents rather than a bare Int64.
  resolveNameMsg read the version off thParams', which on the PFWD path is
  the proxy's session, not the client's. It takes the version as an argument
  now, so each call site passes its own — the forwarded one uses fwdVersion.

  reservedReasonOf matched the reason words before capping, so "internal
  review" became NRRUnknown "internal", which encodes back as NRRInternal.
  Capping precedes the match, so what is kept encodes to what it decoded.

  Four agent tests still pinned NAME NOT_FOUND from a 404 stub, and two spec
  statements still described the old mapping. A registrar that does not
  record labels cannot answer a hashed query, which the resolver README now
  says.
Comment thread src/Simplex/Messaging/Client.hs Outdated
Comment thread src/Simplex/Messaging/Client.hs Outdated
Comment thread src/Simplex/Messaging/Names/Record.hs Outdated
@brenzi

brenzi commented Sep 11, 2026

Copy link
Copy Markdown
Collaborator Author
  • e2e tests green: hardhat (.simplex names v2 contracts) - RESOLVERv2 - SMPv22 - CLIv22
  • test the version matrix pre/post for all stages locally with hardhat (.simplex names v2 contracts)
  • test a v22 client against v22 smp7 against mainnet .testing
  • test a v22 client against stable pre-v22 smpX against mainnet .testing

Version matrix: resolver x SMP relay x client

Run live on a local hardhat chain with the lifecycle fixture, .simplex.

binary build behaviour
relay pre master 200129a max SMP v21, queries /resolve
relay post branch 1cb8146 max SMP v22, queries /v2/resolve
client pre branch, currentClientSMPRelayVersion capped to 21 plaintext query, decodes via oldRegistration
client post branch hashed query, full NameRegistration
resolver pre master 200129a snrc-resolve.py serves /resolve only
resolver post branch serves /v2/resolve, /v1/resolve, /resolve

/name <name>.simplex

relay resolver client alicename (registered) ghostname (never registered)
pre pre pre registered NAME NOT_FOUND
pre pre post registered NAME NOT_FOUND
pre post pre registered NAME NOT_FOUND
pre post post registered NAME NOT_FOUND
post pre pre NAME RESOLVER "HTTP 404" NAME RESOLVER "HTTP 404"
post pre post NAME RESOLVER "HTTP 404" NAME RESOLVER "HTTP 404"
post post pre registered NAME NOT_FOUND
post post post registered, expires 2036-09-08, free to register from 2036-12-07 unless renewed by owner available, $10.00 a
year

Only relay=post + resolver=pre is broken, and it fails every name: /v2/resolve
does not exist on the old resolver, while /health still reports it ready.
Upgrade the resolver before the routers.

An old client against a full v22 stack degrades as specified: bare registered
with no expiry, and NOT_FOUND for a name that is in fact available. Only
post/post/post carries expiry, grace and a price.

Old relay, both resolvers: states the table above does not reach

resolver lapsedname (past grace) barename (registered, no resolver set) heldlapsed (past grace + reserved)
pre registered NAME NOT_FOUND registered
post NAME RESOLVER "HTTP 410" registered NAME RESOLVER "HTTP 410"

Two behaviour changes while the resolver is ahead of the relays. A lapsed name
stops resolving to its stale record, which is the intended fix, but arrives as a
raw 410 because master's mapResolverError has no 410 case. A registered name
with no resolver set flips from NOT_FOUND to resolving with an empty record.

epoberezkin
epoberezkin previously approved these changes Sep 11, 2026
* fix resolver v2 for subnames

* simplify doc
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.

3 participants