Moves electrum client to the jvmAndroid scope

This commit is contained in:
Vitor Pamplona
2026-03-04 10:00:33 -05:00
parent 193561c336
commit 470b1680d0
10 changed files with 146 additions and 101 deletions
@@ -68,6 +68,10 @@ import com.vitorpamplona.quartz.nip03Timestamp.VerificationStateCache
import com.vitorpamplona.quartz.nip03Timestamp.ots.OtsBlockHeightCache import com.vitorpamplona.quartz.nip03Timestamp.ots.OtsBlockHeightCache
import com.vitorpamplona.quartz.nip05DnsIdentifiers.Nip05Client import com.vitorpamplona.quartz.nip05DnsIdentifiers.Nip05Client
import com.vitorpamplona.quartz.nip05DnsIdentifiers.OkHttpNip05Fetcher import com.vitorpamplona.quartz.nip05DnsIdentifiers.OkHttpNip05Fetcher
import com.vitorpamplona.quartz.nip05DnsIdentifiers.namecoin.DEFAULT_ELECTRUMX_SERVERS
import com.vitorpamplona.quartz.nip05DnsIdentifiers.namecoin.ElectrumXClient
import com.vitorpamplona.quartz.nip05DnsIdentifiers.namecoin.NamecoinNameResolver
import com.vitorpamplona.quartz.nip05DnsIdentifiers.namecoin.TOR_ELECTRUMX_SERVERS
import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.Log
import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@@ -143,23 +147,20 @@ class AppModules(
// Custom fetcher that considers tor settings and avoids forwarding. // Custom fetcher that considers tor settings and avoids forwarding.
val nip05Fetcher = OkHttpNip05Fetcher(roleBasedHttpClientBuilder::okHttpClientForNip05) val nip05Fetcher = OkHttpNip05Fetcher(roleBasedHttpClientBuilder::okHttpClientForNip05)
val namecoinElectrumxClient = val namecoinElectrumxClient =
com.vitorpamplona.quartz.nip05.namecoin.ElectrumxClient( ElectrumXClient(
socketFactory = { roleBasedHttpClientBuilder.socketFactoryForNip05() }, socketFactory = { roleBasedHttpClientBuilder.socketFactoryForNip05() },
) )
val namecoinResolver = val namecoinResolver =
com.vitorpamplona.quartz.nip05.namecoin.NamecoinNameResolver( NamecoinNameResolver(
electrumxClient = namecoinElectrumxClient, electrumxClient = namecoinElectrumxClient,
serverListProvider = { serverListProvider = {
if (roleBasedHttpClientBuilder.shouldUseTorForNIP05("https://electrumx.example.com")) { if (roleBasedHttpClientBuilder.shouldUseTorForNIP05("https://electrumx.example.com")) {
com.vitorpamplona.quartz.nip05.namecoin.ElectrumxClient.TOR_SERVERS TOR_ELECTRUMX_SERVERS
} else { } else {
com.vitorpamplona.quartz.nip05.namecoin.ElectrumxClient.DEFAULT_SERVERS DEFAULT_ELECTRUMX_SERVERS
} }
}, },
) )
val namecoinNameService =
com.vitorpamplona.amethyst.service.namecoin.NamecoinNameService
.init(namecoinElectrumxClient)
val nip05Client = Nip05Client(nip05Fetcher, namecoinResolver) val nip05Client = Nip05Client(nip05Fetcher, namecoinResolver)
// Application-wide block height request cache // Application-wide block height request cache
@@ -20,11 +20,11 @@
*/ */
package com.vitorpamplona.amethyst.service.namecoin package com.vitorpamplona.amethyst.service.namecoin
import com.vitorpamplona.quartz.nip05.namecoin.ElectrumxClient import com.vitorpamplona.quartz.nip05DnsIdentifiers.namecoin.ElectrumXClient
import com.vitorpamplona.quartz.nip05.namecoin.ElectrumxServer import com.vitorpamplona.quartz.nip05DnsIdentifiers.namecoin.ElectrumxServer
import com.vitorpamplona.quartz.nip05.namecoin.NamecoinLookupCache import com.vitorpamplona.quartz.nip05DnsIdentifiers.namecoin.NamecoinLookupCache
import com.vitorpamplona.quartz.nip05.namecoin.NamecoinNameResolver import com.vitorpamplona.quartz.nip05DnsIdentifiers.namecoin.NamecoinNameResolver
import com.vitorpamplona.quartz.nip05.namecoin.NamecoinNostrResult import com.vitorpamplona.quartz.nip05DnsIdentifiers.namecoin.NamecoinNostrResult
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.SupervisorJob
@@ -39,7 +39,7 @@ import kotlinx.coroutines.launch
* into Amethyst's existing `ServiceManager` infrastructure. * into Amethyst's existing `ServiceManager` infrastructure.
*/ */
class NamecoinNameService( class NamecoinNameService(
electrumxClient: ElectrumxClient = ElectrumxClient(), electrumxClient: ElectrumXClient,
) { ) {
private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob()) private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
@@ -49,22 +49,6 @@ class NamecoinNameService(
// Custom server list (user-configurable) // Custom server list (user-configurable)
private var customServers: List<ElectrumxServer> = emptyList() private var customServers: List<ElectrumxServer> = emptyList()
companion object {
@Volatile
private var instance: NamecoinNameService? = null
fun getInstance(): NamecoinNameService =
instance ?: throw IllegalStateException(
"NamecoinNameService not initialized. Call init() first.",
)
fun init(electrumxClient: ElectrumxClient): NamecoinNameService =
synchronized(this) {
instance?.let { return it }
NamecoinNameService(electrumxClient).also { instance = it }
}
}
// ── Public API ───────────────────────────────────────────────────── // ── Public API ─────────────────────────────────────────────────────
/** /**
@@ -29,14 +29,14 @@ import androidx.compose.ui.focus.FocusRequester
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.commons.ui.feeds.InvalidatableContent import com.vitorpamplona.amethyst.commons.ui.feeds.InvalidatableContent
import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.service.namecoin.NamecoinNameService
import com.vitorpamplona.amethyst.service.relayClient.searchCommand.SearchQueryState import com.vitorpamplona.amethyst.service.relayClient.searchCommand.SearchQueryState
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
import com.vitorpamplona.quartz.nip05.namecoin.NamecoinNameResolver import com.vitorpamplona.quartz.nip05DnsIdentifiers.namecoin.NamecoinNameResolver
import com.vitorpamplona.quartz.nip10Notes.content.findHashtags import com.vitorpamplona.quartz.nip10Notes.content.findHashtags
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.FlowPreview
@@ -85,7 +85,7 @@ class SearchBarViewModel(
.filter { NamecoinNameResolver.isNamecoinIdentifier(it) } .filter { NamecoinNameResolver.isNamecoinIdentifier(it) }
.map { term -> .map { term ->
try { try {
val result = NamecoinNameService.getInstance().resolve(term) val result = Amethyst.instance.namecoinResolver.resolve(term)
if (result != null) { if (result != null) {
LocalCache.getOrCreateUser(result.pubkey) LocalCache.getOrCreateUser(result.pubkey)
} else { } else {
@@ -21,7 +21,7 @@
package com.vitorpamplona.quartz.nip05DnsIdentifiers package com.vitorpamplona.quartz.nip05DnsIdentifiers
import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.HexKey
import com.vitorpamplona.quartz.nip05.namecoin.NamecoinNameResolver import com.vitorpamplona.quartz.nip05DnsIdentifiers.namecoin.NamecoinNameResolver
import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CancellationException
data class Nip05KeyInfo( data class Nip05KeyInfo(
@@ -0,0 +1,70 @@
/*
* Copyright (c) 2025 Vitor Pamplona
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.quartz.nip05DnsIdentifiers.namecoin
import kotlinx.serialization.Serializable
/**
* Result of an ElectrumX name_show query.
*
* Maps to the JSON fields returned by Namecoin Core / Electrum-NMC:
* { "name": "d/example", "value": "{...}", "txid": "abc...", "height": 12345, ... }
*/
@Serializable
data class NameShowResult(
val name: String,
val value: String,
val txid: String? = null,
val height: Int? = null,
val expiresIn: Int? = null,
)
/**
* Represents a single ElectrumX server endpoint.
*/
data class ElectrumxServer(
val host: String,
val port: Int,
val useSsl: Boolean = true,
/** If true, accept any certificate (self-signed, expired, etc.) */
val trustAllCerts: Boolean = false,
)
/** Well-known public Namecoin ElectrumX servers (clearnet). */
val DEFAULT_ELECTRUMX_SERVERS =
listOf(
ElectrumxServer("electrumx.testls.space", 50002, useSsl = true, trustAllCerts = true),
ElectrumxServer("nmc2.bitcoins.sk", 57002, useSsl = true, trustAllCerts = true),
ElectrumxServer("46.229.238.187", 57002, useSsl = true, trustAllCerts = true),
)
/** Tor-preferred server list: onion primary, clearnet fallback. */
val TOR_ELECTRUMX_SERVERS =
listOf(
ElectrumxServer(
"i665jpwsq46zlsdbnj4axgzd3s56uzey5uhotsnxzsknzbn36jaddsid.onion",
50002,
useSsl = true,
trustAllCerts = true,
),
ElectrumxServer("electrumx.testls.space", 50002, useSsl = true, trustAllCerts = true),
ElectrumxServer("nmc2.bitcoins.sk", 57002, useSsl = true, trustAllCerts = true),
)
@@ -0,0 +1,28 @@
/*
* Copyright (c) 2025 Vitor Pamplona
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.quartz.nip05DnsIdentifiers.namecoin
interface IElectrumXClient {
suspend fun nameShowWithFallback(
identifier: String,
servers: List<ElectrumxServer>,
): NameShowResult?
}
@@ -18,7 +18,7 @@
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
package com.vitorpamplona.quartz.nip05.namecoin package com.vitorpamplona.quartz.nip05DnsIdentifiers.namecoin
import androidx.collection.LruCache import androidx.collection.LruCache
import com.vitorpamplona.quartz.utils.TimeUtils import com.vitorpamplona.quartz.utils.TimeUtils
@@ -18,7 +18,7 @@
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
package com.vitorpamplona.quartz.nip05.namecoin package com.vitorpamplona.quartz.nip05DnsIdentifiers.namecoin
import kotlinx.coroutines.withTimeoutOrNull import kotlinx.coroutines.withTimeoutOrNull
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
@@ -50,9 +50,9 @@ data class NamecoinNostrResult(
* here instead of to the HTTP-based NIP-05 path. * here instead of to the HTTP-based NIP-05 path.
*/ */
class NamecoinNameResolver( class NamecoinNameResolver(
private val electrumxClient: ElectrumxClient = ElectrumxClient(), private val electrumxClient: IElectrumXClient,
private val lookupTimeoutMs: Long = 20_000L, private val lookupTimeoutMs: Long = 20_000L,
private val serverListProvider: () -> List<ElectrumxServer> = { ElectrumxClient.DEFAULT_SERVERS }, private val serverListProvider: () -> List<ElectrumxServer> = { DEFAULT_ELECTRUMX_SERVERS },
) { ) {
private val json = private val json =
Json { Json {
@@ -18,15 +18,16 @@
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
package com.vitorpamplona.quartz.nip05.namecoin package com.vitorpamplona.quartz.nip05DnsIdentifiers.namecoin
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import kotlinx.serialization.Serializable import kotlinx.serialization.builtins.ListSerializer
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonNull
import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.json.buildJsonObject import kotlinx.serialization.json.buildJsonObject
@@ -41,6 +42,8 @@ import java.io.PrintWriter
import java.net.InetSocketAddress import java.net.InetSocketAddress
import java.net.Socket import java.net.Socket
import java.security.MessageDigest import java.security.MessageDigest
import java.security.SecureRandom
import java.security.cert.X509Certificate
import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicInteger
import javax.net.SocketFactory import javax.net.SocketFactory
import javax.net.ssl.SSLContext import javax.net.ssl.SSLContext
@@ -48,32 +51,6 @@ import javax.net.ssl.SSLSocketFactory
import javax.net.ssl.TrustManager import javax.net.ssl.TrustManager
import javax.net.ssl.X509TrustManager import javax.net.ssl.X509TrustManager
/**
* Result of an ElectrumX name_show query.
*
* Maps to the JSON fields returned by Namecoin Core / Electrum-NMC:
* { "name": "d/example", "value": "{...}", "txid": "abc...", "height": 12345, ... }
*/
@Serializable
data class NameShowResult(
val name: String,
val value: String,
val txid: String? = null,
val height: Int? = null,
val expiresIn: Int? = null,
)
/**
* Represents a single ElectrumX server endpoint.
*/
data class ElectrumxServer(
val host: String,
val port: Int,
val useSsl: Boolean = true,
/** If true, accept any certificate (self-signed, expired, etc.) */
val trustAllCerts: Boolean = false,
)
/** /**
* Lightweight, query-only ElectrumX client for Namecoin name resolution. * Lightweight, query-only ElectrumX client for Namecoin name resolution.
* *
@@ -95,11 +72,11 @@ data class ElectrumxServer(
* val result = client.nameShow("d/example", server) * val result = client.nameShow("d/example", server)
* ``` * ```
*/ */
class ElectrumxClient( class ElectrumXClient(
private val connectTimeoutMs: Long = 10_000L, private val connectTimeoutMs: Long = 10_000L,
private val readTimeoutMs: Long = 15_000L, private val readTimeoutMs: Long = 15_000L,
private val socketFactory: () -> SocketFactory = { SocketFactory.getDefault() }, private val socketFactory: () -> SocketFactory = { SocketFactory.getDefault() },
) { ) : IElectrumXClient {
private val json = private val json =
Json { Json {
ignoreUnknownKeys = true ignoreUnknownKeys = true
@@ -109,27 +86,6 @@ class ElectrumxClient(
private val mutex = Mutex() private val mutex = Mutex()
companion object { companion object {
/** Well-known public Namecoin ElectrumX servers (clearnet). */
val DEFAULT_SERVERS =
listOf(
ElectrumxServer("electrumx.testls.space", 50002, useSsl = true, trustAllCerts = true),
ElectrumxServer("nmc2.bitcoins.sk", 57002, useSsl = true, trustAllCerts = true),
ElectrumxServer("46.229.238.187", 57002, useSsl = true, trustAllCerts = true),
)
/** Tor-preferred server list: onion primary, clearnet fallback. */
val TOR_SERVERS =
listOf(
ElectrumxServer(
"i665jpwsq46zlsdbnj4axgzd3s56uzey5uhotsnxzsknzbn36jaddsid.onion",
50002,
useSsl = true,
trustAllCerts = true,
),
ElectrumxServer("electrumx.testls.space", 50002, useSsl = true, trustAllCerts = true),
ElectrumxServer("nmc2.bitcoins.sk", 57002, useSsl = true, trustAllCerts = true),
)
private const val PROTOCOL_VERSION = "1.4" private const val PROTOCOL_VERSION = "1.4"
/** /**
@@ -162,7 +118,7 @@ class ElectrumxClient(
*/ */
suspend fun nameShow( suspend fun nameShow(
identifier: String, identifier: String,
server: ElectrumxServer = DEFAULT_SERVERS.first(), server: ElectrumxServer = DEFAULT_ELECTRUMX_SERVERS.first(),
): NameShowResult? = ): NameShowResult? =
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
mutex.withLock { mutex.withLock {
@@ -180,11 +136,11 @@ class ElectrumxClient(
* Try each server in order until one succeeds. * Try each server in order until one succeeds.
* *
* @param identifier Full Namecoin name, e.g. "d/example" * @param identifier Full Namecoin name, e.g. "d/example"
* @param servers Ordered server list to try; defaults to [DEFAULT_SERVERS] * @param servers Ordered server list to try; defaults to [DEFAULT_ELECTRUMX_SERVERS]
*/ */
suspend fun nameShowWithFallback( override suspend fun nameShowWithFallback(
identifier: String, identifier: String,
servers: List<ElectrumxServer> = DEFAULT_SERVERS, servers: List<ElectrumxServer>,
): NameShowResult? { ): NameShowResult? {
for (server in servers) { for (server in servers) {
val result = nameShow(identifier, server) val result = nameShow(identifier, server)
@@ -329,7 +285,7 @@ class ElectrumxClient(
private fun parseHistoryResponse(raw: String): List<Pair<String, Int>>? { private fun parseHistoryResponse(raw: String): List<Pair<String, Int>>? {
val envelope = json.parseToJsonElement(raw).jsonObject val envelope = json.parseToJsonElement(raw).jsonObject
val error = envelope["error"] val error = envelope["error"]
if (error != null && error !is kotlinx.serialization.json.JsonNull) return null if (error != null && error !is JsonNull) return null
val result = envelope["result"]?.jsonArray ?: return null val result = envelope["result"]?.jsonArray ?: return null
return result.mapNotNull { entry -> return result.mapNotNull { entry ->
@@ -354,7 +310,7 @@ class ElectrumxClient(
): NameShowResult? { ): NameShowResult? {
val envelope = json.parseToJsonElement(raw).jsonObject val envelope = json.parseToJsonElement(raw).jsonObject
val error = envelope["error"] val error = envelope["error"]
if (error != null && error !is kotlinx.serialization.json.JsonNull) return null if (error != null && error !is JsonNull) return null
val result = envelope["result"]?.jsonObject ?: return null val result = envelope["result"]?.jsonObject ?: return null
val vouts = result["vout"]?.jsonArray ?: return null val vouts = result["vout"]?.jsonArray ?: return null
@@ -505,20 +461,20 @@ class ElectrumxClient(
arrayOf<TrustManager>( arrayOf<TrustManager>(
object : X509TrustManager { object : X509TrustManager {
override fun checkClientTrusted( override fun checkClientTrusted(
chain: Array<java.security.cert.X509Certificate>, chain: Array<X509Certificate>,
authType: String, authType: String,
) {} ) {}
override fun checkServerTrusted( override fun checkServerTrusted(
chain: Array<java.security.cert.X509Certificate>, chain: Array<X509Certificate>,
authType: String, authType: String,
) {} ) {}
override fun getAcceptedIssuers(): Array<java.security.cert.X509Certificate> = arrayOf() override fun getAcceptedIssuers(): Array<X509Certificate> = arrayOf()
}, },
) )
val sslContext = SSLContext.getInstance("TLS") val sslContext = SSLContext.getInstance("TLS")
sslContext.init(null, trustAllCerts, java.security.SecureRandom()) sslContext.init(null, trustAllCerts, SecureRandom())
return sslContext.socketFactory return sslContext.socketFactory
} }
@@ -535,8 +491,8 @@ class ElectrumxClient(
put( put(
"params", "params",
json.encodeToJsonElement( json.encodeToJsonElement(
kotlinx.serialization.builtins.ListSerializer( ListSerializer(
kotlinx.serialization.json.JsonElement JsonElement
.serializer(), .serializer(),
), ),
params.map { params.map {
@@ -20,6 +20,8 @@
*/ */
package com.vitorpamplona.quartz.nip05.namecoin package com.vitorpamplona.quartz.nip05.namecoin
import com.vitorpamplona.quartz.nip05DnsIdentifiers.namecoin.NamecoinNameResolver
import com.vitorpamplona.quartz.nip05DnsIdentifiers.namecoin.NamecoinNostrResult
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotNull import org.junit.Assert.assertNotNull
@@ -267,7 +269,11 @@ class NamecoinNameResolverTest {
} catch (_: Exception) { } catch (_: Exception) {
emptyList() emptyList()
} }
return NamecoinNostrResult(pubkey = pubkey.lowercase(), relays = relays, namecoinName = namecoinName) return NamecoinNostrResult(
pubkey = pubkey.lowercase(),
relays = relays,
namecoinName = namecoinName,
)
} }
} }
return null return null