ee418bdd0a
Fixes discovered while porting Namecoin NIP-05 to Primal Android (PrimalHQ/primal-android-app#934): 1. Race condition: stale intermediate lookups overwrite final result - Changed map to mapLatest in SearchBarViewModel so that previous in-flight ElectrumX lookups are cancelled when the query changes - Without this, typing 'd/testls' character by character causes stale results from 'd/test', 'd/testl' etc. to arrive after the correct 'd/testls' result and overwrite it with null 2. CancellationException swallowed in catch block - mapLatest cancels previous coroutines via CancellationException - The generic catch was catching it and emitting null, wiping the valid result. Now re-throws CancellationException 3. Root lookup fails when names object has no underscore key - extractFromDomainValue tried names[localPart] then names[underscore] which is the same thing for root lookups - Now falls back to first available entry for root lookups when no underscore key exists - Non-root lookups still fail correctly (no false matches) 4. Global Mutex serializes all lookups - Single Mutex in ElectrumxClient blocked unrelated lookups to different servers. A 25s timeout on one server stalled everything - Now uses per-server mutexes via ConcurrentHashMap 5. customServers set but never read - NamecoinNameService.setCustomServers() stored the list but the resolver was constructed with the default serverListProvider - Now wires customServers through to the resolver 6. resolveLive uses orphaned CoroutineScope - Now accepts an optional external scope parameter so callers can tie resolution to their own lifecycle Adds 2 new tests: root fallback to first entry, non-root no-fallback.