fix: check Namecoin name expiry before resolving
Query current block height via blockchain.headers.subscribe and reject names that have expired (>= 36000 blocks since last update). Populate expiresIn field in NameShowResult for downstream use. Unconfirmed transactions (height <= 0) are treated as active.
This commit is contained in:
+45
-2
@@ -131,6 +131,13 @@ class ElectrumxClient(
|
||||
|
||||
private const val PROTOCOL_VERSION = "1.4"
|
||||
|
||||
/**
|
||||
* Namecoin names expire this many blocks after their last update.
|
||||
* From chainparams.cpp: consensus.nNameExpirationDepth = 36000
|
||||
* (~250 days at ~10 min/block).
|
||||
*/
|
||||
const val NAME_EXPIRE_DEPTH = 36_000
|
||||
|
||||
// Namecoin script opcodes
|
||||
private const val OP_NAME_UPDATE: Byte = 0x53 // OP_3 repurposed by Namecoin
|
||||
private const val OP_2DROP: Byte = 0x6d
|
||||
@@ -222,8 +229,28 @@ class ElectrumxClient(
|
||||
writer.println(txReq)
|
||||
val txResponse = reader.readLine() ?: return null
|
||||
|
||||
// 5. Parse the name value from the transaction
|
||||
return parseNameFromTransaction(identifier, txHash, height, txResponse)
|
||||
// 5. Get current block height to check name expiry
|
||||
val headersReq = buildRpcRequest("blockchain.headers.subscribe", emptyList<String>())
|
||||
writer.println(headersReq)
|
||||
val headersResponse = reader.readLine()
|
||||
val currentHeight = parseBlockHeight(headersResponse)
|
||||
|
||||
// 6. Check if the name has expired
|
||||
if (currentHeight != null && height > 0) {
|
||||
val blocksSinceUpdate = currentHeight - height
|
||||
if (blocksSinceUpdate >= NAME_EXPIRE_DEPTH) {
|
||||
return null // Name has expired
|
||||
}
|
||||
}
|
||||
|
||||
// 7. Parse the name value from the transaction
|
||||
val result = parseNameFromTransaction(identifier, txHash, height, txResponse)
|
||||
// Populate expiresIn if we know the current height
|
||||
return if (result != null && currentHeight != null && height > 0) {
|
||||
result.copy(expiresIn = NAME_EXPIRE_DEPTH - (currentHeight - height))
|
||||
} else {
|
||||
result
|
||||
}
|
||||
} finally {
|
||||
runCatching { writer.close() }
|
||||
runCatching { reader.close() }
|
||||
@@ -279,6 +306,22 @@ class ElectrumxClient(
|
||||
return digest.reversedArray().joinToString("") { "%02x".format(it) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the block height from a `blockchain.headers.subscribe` response.
|
||||
*
|
||||
* Response format: {"result": {"height": 814300, "hex": "..."}, ...}
|
||||
*/
|
||||
private fun parseBlockHeight(raw: String?): Int? {
|
||||
if (raw == null) return null
|
||||
return try {
|
||||
val envelope = json.parseToJsonElement(raw).jsonObject
|
||||
val result = envelope["result"]?.jsonObject ?: return null
|
||||
result["height"]?.jsonPrimitive?.int
|
||||
} catch (_: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the history response into a list of (txHash, height) pairs.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user