shrink diff

This commit is contained in:
Alain Brenzikofer
2026-09-22 16:40:59 +02:00
parent 3ae71f06b4
commit 2ffec2aad6
4 changed files with 26 additions and 52 deletions
+5 -18
View File
@@ -890,24 +890,11 @@ def owned_by(address: str, offset: int = 0):
"""Every name an address holds, across every configured TLD, with the
account's on-chain footprint.
Read off the ERC-721 registrar rather than from logs: the token is the
name, so `balanceOf` / `tokenOfOwnerByIndex` is the current answer and it
includes names acquired by transfer, which a scan of registration events
would miss. `labelOf` returns the plaintext label, recorded write-once at
registration, so no off-chain index is needed to turn a token id back into
a name.
Enumeration is deliberately not maintained on expiry, so a lapsed name
stays in the list until someone re-registers it. That is reported rather
than filtered: every entry carries `status`, using the same vocabulary as
/resolve, and a caller scanning a recovered key is exactly the caller who
needs to be told one of its names can still be renewed.
`inUse` answers the question a recovery scan actually asks - has this
account ever been used - which holding a name is only one way to be. An
account that was funded or ever sent a transaction is in use even with no
name, so the nonce and balance it is derived from are reported too: a scan
that gets this wrong hands out an account its owner is already using.
Enumeration is read off the ERC-721 registrar, so a name acquired by
transfer counts, and a lapsed one stays listed until re-registered - it is
reported with its `status`, not filtered. `inUse` is what a recovery scan
asks; holding a name is only one way to be in use, so the nonce and balance
it is derived from are reported too.
"""
if not is_address(address):
return 400, {
+2 -2
View File
@@ -1281,12 +1281,12 @@ deleteLocalInvShortLink' c (CSLInvitation _ srv linkId _) = withStore' c $ \db -
ownedSimplexNames' :: AgentClient -> NetworkRequestMode -> UserId -> [SMPServer] -> Address -> Word32 -> AM (SMPServer, OwnedNames)
ownedSimplexNames' c nm userId used addr offset = do
srv <- getNextNameServerAvoiding c userId used
srv <- getNextNameServer c userId used
(srv,) <$> ownedNames c nm userId srv addr offset
resolveSimplexName' :: AgentClient -> NetworkRequestMode -> UserId -> SimplexDomain -> AM NameResponse
resolveSimplexName' c nm userId domain = do
resolverSrv <- getNextNameServer c userId
resolverSrv <- getNextNameServer c userId []
resolveName c nm userId resolverSrv domain
changeConnectionUser' :: AgentClient -> UserId -> ConnId -> UserId -> AM ()
+8 -21
View File
@@ -71,7 +71,6 @@ module Simplex.Messaging.Agent.Client
getQueueLink,
resolveName,
ownedNames,
getNextNameServerAvoiding,
getNextNameServer,
enableQueueNotifications,
EnableQueueNtfReq (..),
@@ -260,9 +259,9 @@ import Simplex.Messaging.Crypto.BBS (BBSPresHeader (..), BBSPublicKey)
import Simplex.Messaging.Crypto.Entitlement (EntitlementCredential, EntitlementProof, generateEntitlementProof)
import Simplex.Messaging.Encoding
import Simplex.Messaging.Encoding.String
import Simplex.Messaging.Notifications.Client
import Simplex.Messaging.Eth.Address (Address)
import Simplex.Messaging.Names.Record (OwnedNames)
import Simplex.Messaging.Notifications.Client
import Simplex.Messaging.Notifications.Protocol
import Simplex.Messaging.Notifications.Transport (NTFVersion)
import Simplex.Messaging.Notifications.Types
@@ -2042,32 +2041,20 @@ ownedNames c nm userId server addr offset =
ownedViaProxy smp proxySess = proxyOwnedNames smp nm proxySess addr offset
ownedDirectly smp = directOwnedNames smp nm addr offset
-- | A names-capable server the caller has not used yet. A scan asks about one
-- account per relay, because sending the whole list to one relay would tell it
-- those accounts belong to one wallet. With fewer relays than accounts the
-- choice wraps onto used ones, which is the best the configured set allows.
getNextNameServerAvoiding :: AgentClient -> UserId -> [SMPServer] -> AM SMPServer
getNextNameServerAvoiding c userId used =
liftIO (TM.lookupIO userId (userServers c :: TMap UserId (UserServers 'PSMP))) >>= \case
Just UserServers {nameSrvs} ->
let unused = filter ((`notElem` used) . protoServer . snd) nameSrvs
in case L.nonEmpty unused of
Just srvs -> protoServer <$> pickServer srvs
Nothing -> case L.nonEmpty nameSrvs of
Just srvs -> protoServer <$> pickServer srvs
Nothing -> throwE NO_NAME_SERVERS
Nothing -> throwE $ INTERNAL "unknown userId - no user servers"
-- | Pick a names-capable server for the user (the agent owns server selection,
-- accounting for the names role). nameSrvs is opt-in (a plain list); empty means
-- no server resolves names - a declared agent error, never a fallback.
getNextNameServer :: AgentClient -> UserId -> AM SMPServer
getNextNameServer c userId =
-- Servers already used are avoided where the set allows: one relay asked about
-- every account of a scan would learn they belong to one wallet.
getNextNameServer :: AgentClient -> UserId -> [SMPServer] -> AM SMPServer
getNextNameServer c userId usedSrvs =
liftIO (TM.lookupIO userId (userServers c :: TMap UserId (UserServers 'PSMP))) >>= \case
Just UserServers {nameSrvs} -> case L.nonEmpty nameSrvs of
Just srvs -> protoServer <$> pickServer srvs
Just srvs -> protoServer <$> pickServer (fromMaybe srvs $ L.nonEmpty $ L.filter (isUnusedServer usedHosts) srvs)
Nothing -> throwE NO_NAME_SERVERS
Nothing -> throwE $ INTERNAL "unknown userId - no user servers"
where
usedHosts = S.unions $ map serverHosts usedSrvs
enableQueueNotifications :: AgentClient -> RcvQueue -> SMP.NtfPublicAuthKey -> SMP.RcvNtfPublicDhKey -> AM (SMP.NotifierId, SMP.RcvNtfPublicDhKey)
enableQueueNotifications c rq@RcvQueue {rcvId, rcvPrivateKey} notifierKey rcvNtfPublicDhKey =
+11 -11
View File
@@ -68,6 +68,17 @@ pingEndpoint NamesEnv {resolverEnv, config} =
resolveName :: NamesEnv -> NameQuery -> IO (Either NameErrorType NameResponse)
resolveName env q = resolverCall env $ fetch env q
-- | Bound the call by the configured timeout, and report a raised exception as an error, leaving async exceptions alone.
resolverCall :: NamesEnv -> IO (Either NameErrorType a) -> IO (Either NameErrorType a)
resolverCall env a =
E.try (timeout (resolverTimeoutMs (config env) * 1000) a) >>= \case
Right result -> pure (fromMaybe (Left (RESOLVER "timeout")) result)
Left e
| Just (_ :: E.SomeAsyncException) <- E.fromException e -> E.throwIO e
| otherwise -> do
logError $ "[NAMES] resolver fetch raised " <> T.pack (E.displayException e)
pure (Left (RESOLVER "resolver error"))
fetch :: NamesEnv -> NameQuery -> IO (Either NameErrorType NameResponse)
fetch NamesEnv {resolverEnv} q =
first mapResolverError <$> resolveHttp resolverEnv (decodeLatin1 $ smpEncode q)
@@ -80,17 +91,6 @@ fetchOwned :: NamesEnv -> Address -> Word32 -> IO (Either NameErrorType OwnedNam
fetchOwned NamesEnv {resolverEnv} addr offset =
first mapResolverError <$> ownedByHttp resolverEnv (decodeLatin1 $ strEncode addr) offset
-- | Bound the call by the configured timeout, and report a raised exception as an error, leaving async exceptions alone.
resolverCall :: NamesEnv -> IO (Either NameErrorType a) -> IO (Either NameErrorType a)
resolverCall env a =
E.try (timeout (resolverTimeoutMs (config env) * 1000) a) >>= \case
Right result -> pure (fromMaybe (Left (RESOLVER "timeout")) result)
Left e
| Just (_ :: E.SomeAsyncException) <- E.fromException e -> E.throwIO e
| otherwise -> do
logError $ "[NAMES] resolver fetch raised " <> T.pack (E.displayException e)
pure (Left (RESOLVER "resolver error"))
mapResolverError :: ResolverError -> NameErrorType
mapResolverError = \case
HttpStatusErr code -> RESOLVER ("HTTP " <> T.pack (show code))