mirror of
https://github.com/simplex-chat/simplexmq.git
synced 2026-11-04 08:37:49 +00:00
RFC and fixes
This commit is contained in:
1 parent
adcdb54c02
commit
861e9890c6
3 files changed
+80
-1
No files matched your search
+1
-1
@@ -10,7 +10,7 @@ Crypto:
|
||||
SMP protocol:
|
||||
- `ROWN` command (v23): the names an address owns, and whether the account has
|
||||
been used at all, so a recovered wallet seed can be scanned for the accounts
|
||||
already in use.
|
||||
already in use. See `plans/2026-09-22-names-owned-by.md`.
|
||||
|
||||
# 6.5.1
|
||||
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
# Owned-by: the names an address owns
|
||||
|
||||
A recovered seed does not say how many of its accounts have been used. Until it
|
||||
does, a restored device cannot take a fresh account without risking one its
|
||||
owner already has, and cannot find the names it already holds. This adds the
|
||||
question the protocol could not ask: what does this address own.
|
||||
|
||||
This is Workstream B of the SimpleX names v2 plan, after the Ethereum crypto
|
||||
primitives. The client consumer is the wallet recovery scan in simplex-chat.
|
||||
|
||||
## What this delivers
|
||||
|
||||
```
|
||||
GET /v2/owned-by/<address>?offset=N resolver, JSON OwnedNames
|
||||
ROWN <address> <offset> -> ROWND SMP v23 (nameOwnedSMPVersion)
|
||||
ownedNames server, agent client, agent
|
||||
```
|
||||
|
||||
The agent returns the relay it used alongside the answer, so a caller can pass
|
||||
it back as used and ask the next account elsewhere. Sending every account of a
|
||||
seed to one relay would tell that relay the accounts belong to one wallet; the
|
||||
scan therefore asks one account per relay, and `getNextNameServer` avoids the
|
||||
hosts already used where the configured set allows. `proxiedSMPRelayVersion` is
|
||||
pinned to the current version so ROWN can be proxied at all — a scan that falls
|
||||
back to a direct session hands the relay its address with its IP.
|
||||
|
||||
Enumeration is read off the ERC-721 registrar (`balanceOf`,
|
||||
`tokenOfOwnerByIndex`, `labelOf`), not from registration logs: the token is the
|
||||
name, so a name acquired by transfer counts. The registrar does not maintain
|
||||
enumeration on expiry — it states this as an invariant, and burns a token only
|
||||
when the name is re-registered — so a lapsed name stays listed. It is reported
|
||||
with its `status` rather than filtered, because a caller scanning a recovered
|
||||
seed is exactly the caller who needs to be told a name can still be renewed.
|
||||
|
||||
## What `inUse` actually answers
|
||||
|
||||
`inUse` is `holds a name now, or nonce > 0, or balance > 0`, on the one chain
|
||||
the resolver is configured with. Holding a name is only one way for an account
|
||||
to be in use: an account that was funded, or ever sent a transaction, is in use
|
||||
with no name, and a scan that reads names alone hands out an account its owner
|
||||
is already using. Within that scope the signal is sound — an EOA's balance can
|
||||
only fall through its own transaction, which bumps the nonce, so "funded then
|
||||
drained" still reads as used, and an EIP-7702 delegation leaves the authority's
|
||||
nonce incremented, so it needs no separate code check.
|
||||
|
||||
It does not see:
|
||||
|
||||
- **Accounts holding only other tokens.** An EOA can hold ERC-20s or NFTs with
|
||||
nonce 0 and no ether. ERC-20 has no reverse index, so answering this needs
|
||||
`eth_getLogs` over Transfer topics for all history, which providers cap, or an
|
||||
external indexer. Out of scope here.
|
||||
- **Accounts used on another chain.** The same key is the same address on every
|
||||
L2 and sidechain; this chain's nonce and balance stay 0.
|
||||
- **History, as opposed to current state.** `balanceOf` is present ownership. A
|
||||
name registered for an account by a controller — which leaves the owner at
|
||||
nonce 0 — and later transferred away, or lapsed and re-registered by someone
|
||||
else, leaves no trace.
|
||||
|
||||
The cost is bounded. A name-holding account is always found, so no account that
|
||||
holds a name is ever mislabelled. A missed account matters only as a gap-limit
|
||||
reset: the scan can stop up to `scanGapLimit` indexes early and not reach a name
|
||||
beyond that. That is recovery incompleteness, recoverable by scanning again on a
|
||||
better signal, not loss. In the other direction a dust transfer marks an account
|
||||
used; the indexes come from hardened derivation with no published xpub, so they
|
||||
cannot be enumerated to be dusted.
|
||||
|
||||
## What is deliberately absent
|
||||
|
||||
- **No token or indexer integration**, per the limits above.
|
||||
- **Nonce and balance are not carried over SMP.** The resolver reports them, and
|
||||
`OwnedNames` keeps only the names, the flag and the cursor, so a client cannot
|
||||
yet see why an account is in use.
|
||||
- **No caching.** One owned-by is many `eth_call`s, so it is forked on the
|
||||
server the same way RSLV is, and nothing is memoised.
|
||||
- **Enumeration is not atomic.** `balanceOf` and each `tokenOfOwnerByIndex` are
|
||||
separate calls at `latest`, so a transfer between them can duplicate or skip an
|
||||
entry, and successive pages can straddle blocks. Pinning every call to one
|
||||
block number is the fix if it ever matters for a recovery scan.
|
||||
@@ -178,6 +178,7 @@ smpBlockSize = 16384
|
||||
-- 20 - public namespaces resolver, RSLV command (6/20/2026)
|
||||
-- 21 - server public information in handshake (7/5/2026)
|
||||
-- 22 - RNAME answers name availability as well as the record (7/25/2026)
|
||||
-- 23 - ROWN command, the names an address owns (9/22/2026)
|
||||
|
||||
data SMPVersion
|
||||
|
||||
|
||||
Reference in new issue
Block a user