Node client_type & client_version not parsed for non-eth chains (#467)

* Fix labels fill

* return null in case of unknown client type
This commit is contained in:
Anton
2024-05-07 14:38:04 +03:00
committed by GitHub
parent 5f62838e38
commit 65c383ac69
7 changed files with 70 additions and 33 deletions

1
.gitignore vendored
View File

@@ -2,6 +2,7 @@
build/ build/
out/ out/
./dshackle.yaml ./dshackle.yaml
dshackle.yaml
./upstream.yaml ./upstream.yaml
testsetup/ testsetup/
.idea/ .idea/

View File

@@ -11,6 +11,7 @@ import reactor.core.publisher.Mono
const val UNKNOWN_CLIENT_VERSION = "unknown" const val UNKNOWN_CLIENT_VERSION = "unknown"
typealias UpstreamSettingsDetectorBuilder = (Chain, Upstream) -> UpstreamSettingsDetector? typealias UpstreamSettingsDetectorBuilder = (Chain, Upstream) -> UpstreamSettingsDetector?
abstract class UpstreamSettingsDetector( abstract class UpstreamSettingsDetector(
private val upstream: Upstream, private val upstream: Upstream,
) { ) {
@@ -34,10 +35,12 @@ abstract class UpstreamSettingsDetector(
protected abstract fun parseClientVersion(data: ByteArray): String protected abstract fun parseClientVersion(data: ByteArray): String
} }
abstract class BasicEthUpstreamSettingsDetector( abstract class BasicUpstreamSettingsDetector(
private val upstream: Upstream, private val upstream: Upstream,
) : UpstreamSettingsDetector(upstream) { ) : UpstreamSettingsDetector(upstream) {
protected abstract fun nodeTypeRequest(): NodeTypeRequest protected abstract fun nodeTypeRequest(): NodeTypeRequest
protected abstract fun clientVersion(node: JsonNode): String?
protected abstract fun clientType(node: JsonNode): String?
protected fun detectNodeType(): Flux<Pair<String, String>?> { protected fun detectNodeType(): Flux<Pair<String, String>?> {
val nodeTypeRequest = nodeTypeRequest() val nodeTypeRequest = nodeTypeRequest()
@@ -47,25 +50,30 @@ abstract class BasicEthUpstreamSettingsDetector(
.flatMap(ChainResponse::requireResult) .flatMap(ChainResponse::requireResult)
.map { Global.objectMapper.readValue<JsonNode>(it) } .map { Global.objectMapper.readValue<JsonNode>(it) }
.flatMapMany { node -> .flatMapMany { node ->
val mappedNode = nodeTypeRequest.mapper(node)
val labels = mutableListOf<Pair<String, String>>() val labels = mutableListOf<Pair<String, String>>()
if (mappedNode.isTextual) { clientType(node)?.let {
clientType(mappedNode.textValue())?.let { labels.add("client_type" to it)
labels.add("client_type" to it) }
} clientVersion(node)?.let {
clientVersion(mappedNode.textValue())?.let { labels.add("client_version" to it)
labels.add("client_version" to it)
}
} }
Flux.fromIterable(labels) Flux.fromIterable(labels)
} }
.onErrorResume { .onErrorResume { error ->
log.warn("Can't detect the node type of upstream ${upstream.getId()}, reason - {}", error.message)
Flux.empty() Flux.empty()
} }
} }
}
private fun clientVersion(client: String): String? { abstract class BasicEthUpstreamSettingsDetector(
upstream: Upstream,
) : BasicUpstreamSettingsDetector(upstream) {
abstract fun mapping(node: JsonNode): String
override fun clientVersion(node: JsonNode): String? {
val client = mapping(node)
val firstSlash = client.indexOf("/") val firstSlash = client.indexOf("/")
val secondSlash = client.indexOf("/", firstSlash + 1) val secondSlash = client.indexOf("/", firstSlash + 1)
if (firstSlash == -1 || secondSlash == -1 || secondSlash < firstSlash) { if (firstSlash == -1 || secondSlash == -1 || secondSlash < firstSlash) {
@@ -74,7 +82,8 @@ abstract class BasicEthUpstreamSettingsDetector(
return client.substring(firstSlash + 1, secondSlash) return client.substring(firstSlash + 1, secondSlash)
} }
private fun clientType(client: String): String? { override fun clientType(node: JsonNode): String? {
val client = mapping(node)
val firstSlash = client.indexOf("/") val firstSlash = client.indexOf("/")
if (firstSlash == -1) { if (firstSlash == -1) {
log.debug("Unknown client type: {}", client) log.debug("Unknown client type: {}", client)
@@ -82,9 +91,8 @@ abstract class BasicEthUpstreamSettingsDetector(
} }
return client.substring(0, firstSlash).lowercase() return client.substring(0, firstSlash).lowercase()
} }
data class NodeTypeRequest(
val request: ChainRequest,
val mapper: (JsonNode) -> JsonNode,
)
} }
data class NodeTypeRequest(
val request: ChainRequest,
)

View File

@@ -1,11 +1,11 @@
package io.emeraldpay.dshackle.upstream.beaconchain package io.emeraldpay.dshackle.upstream.beaconchain
import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.node.NullNode
import com.fasterxml.jackson.module.kotlin.readValue import com.fasterxml.jackson.module.kotlin.readValue
import io.emeraldpay.dshackle.Global import io.emeraldpay.dshackle.Global
import io.emeraldpay.dshackle.upstream.BasicEthUpstreamSettingsDetector import io.emeraldpay.dshackle.upstream.BasicEthUpstreamSettingsDetector
import io.emeraldpay.dshackle.upstream.ChainRequest import io.emeraldpay.dshackle.upstream.ChainRequest
import io.emeraldpay.dshackle.upstream.NodeTypeRequest
import io.emeraldpay.dshackle.upstream.UNKNOWN_CLIENT_VERSION import io.emeraldpay.dshackle.upstream.UNKNOWN_CLIENT_VERSION
import io.emeraldpay.dshackle.upstream.Upstream import io.emeraldpay.dshackle.upstream.Upstream
import io.emeraldpay.dshackle.upstream.rpcclient.RestParams import io.emeraldpay.dshackle.upstream.rpcclient.RestParams
@@ -18,9 +18,7 @@ class BeaconChainUpstreamSettingsDetector(
override fun nodeTypeRequest(): NodeTypeRequest { override fun nodeTypeRequest(): NodeTypeRequest {
return NodeTypeRequest( return NodeTypeRequest(
clientVersionRequest(), clientVersionRequest(),
) { node -> )
node.get("data")?.get("version") ?: NullNode.instance
}
} }
override fun detectLabels(): Flux<Pair<String, String>> { override fun detectLabels(): Flux<Pair<String, String>> {
@@ -29,6 +27,10 @@ class BeaconChainUpstreamSettingsDetector(
) )
} }
override fun mapping(node: JsonNode): String {
return node.get("data")?.get("version")?.asText() ?: ""
}
override fun clientVersionRequest(): ChainRequest { override fun clientVersionRequest(): ChainRequest {
return ChainRequest("GET#/eth/v1/node/version", RestParams.emptyParams()) return ChainRequest("GET#/eth/v1/node/version", RestParams.emptyParams())
} }

View File

@@ -1,9 +1,11 @@
package io.emeraldpay.dshackle.upstream.ethereum package io.emeraldpay.dshackle.upstream.ethereum
import com.fasterxml.jackson.databind.JsonNode
import io.emeraldpay.dshackle.Chain import io.emeraldpay.dshackle.Chain
import io.emeraldpay.dshackle.upstream.BasicEthUpstreamSettingsDetector import io.emeraldpay.dshackle.upstream.BasicEthUpstreamSettingsDetector
import io.emeraldpay.dshackle.upstream.ChainRequest import io.emeraldpay.dshackle.upstream.ChainRequest
import io.emeraldpay.dshackle.upstream.ChainResponse import io.emeraldpay.dshackle.upstream.ChainResponse
import io.emeraldpay.dshackle.upstream.NodeTypeRequest
import io.emeraldpay.dshackle.upstream.Upstream import io.emeraldpay.dshackle.upstream.Upstream
import io.emeraldpay.dshackle.upstream.rpcclient.ListParams import io.emeraldpay.dshackle.upstream.rpcclient.ListParams
import reactor.core.publisher.Flux import reactor.core.publisher.Flux
@@ -24,6 +26,10 @@ class EthereumUpstreamSettingsDetector(
) )
} }
override fun mapping(node: JsonNode): String {
return node.asText()
}
override fun clientVersionRequest(): ChainRequest { override fun clientVersionRequest(): ChainRequest {
return ChainRequest("web3_clientVersion", ListParams()) return ChainRequest("web3_clientVersion", ListParams())
} }
@@ -54,9 +60,5 @@ class EthereumUpstreamSettingsDetector(
).flatMap(ChainResponse::requireResult) ).flatMap(ChainResponse::requireResult)
} }
override fun nodeTypeRequest(): NodeTypeRequest { override fun nodeTypeRequest(): NodeTypeRequest = NodeTypeRequest(clientVersionRequest())
return NodeTypeRequest(
clientVersionRequest(),
) { node -> node }
}
} }

View File

@@ -2,19 +2,24 @@ package io.emeraldpay.dshackle.upstream.near
import com.fasterxml.jackson.annotation.JsonIgnoreProperties import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.module.kotlin.readValue import com.fasterxml.jackson.module.kotlin.readValue
import io.emeraldpay.dshackle.Global import io.emeraldpay.dshackle.Global
import io.emeraldpay.dshackle.upstream.BasicUpstreamSettingsDetector
import io.emeraldpay.dshackle.upstream.ChainRequest import io.emeraldpay.dshackle.upstream.ChainRequest
import io.emeraldpay.dshackle.upstream.NodeTypeRequest
import io.emeraldpay.dshackle.upstream.UNKNOWN_CLIENT_VERSION
import io.emeraldpay.dshackle.upstream.Upstream import io.emeraldpay.dshackle.upstream.Upstream
import io.emeraldpay.dshackle.upstream.UpstreamSettingsDetector
import io.emeraldpay.dshackle.upstream.rpcclient.ListParams import io.emeraldpay.dshackle.upstream.rpcclient.ListParams
import reactor.core.publisher.Flux import reactor.core.publisher.Flux
class NearUpstreamSettingsDetector( class NearUpstreamSettingsDetector(
upstream: Upstream, upstream: Upstream,
) : UpstreamSettingsDetector(upstream) { ) : BasicUpstreamSettingsDetector(upstream) {
override fun detectLabels(): Flux<Pair<String, String>> { override fun detectLabels(): Flux<Pair<String, String>> {
return Flux.empty() return Flux.merge(
detectNodeType(),
)
} }
override fun clientVersionRequest(): ChainRequest { override fun clientVersionRequest(): ChainRequest {
@@ -36,4 +41,11 @@ class NearUpstreamSettingsDetector(
@JsonProperty("version") @JsonProperty("version")
val version: String, val version: String,
) )
override fun nodeTypeRequest(): NodeTypeRequest = NodeTypeRequest(clientVersionRequest())
override fun clientType(node: JsonNode): String? = null
override fun clientVersion(node: JsonNode): String? =
node.get("version")?.get("version")?.asText() ?: UNKNOWN_CLIENT_VERSION
} }

View File

@@ -2,19 +2,24 @@ package io.emeraldpay.dshackle.upstream.solana
import com.fasterxml.jackson.annotation.JsonIgnoreProperties import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.module.kotlin.readValue import com.fasterxml.jackson.module.kotlin.readValue
import io.emeraldpay.dshackle.Global import io.emeraldpay.dshackle.Global
import io.emeraldpay.dshackle.upstream.BasicUpstreamSettingsDetector
import io.emeraldpay.dshackle.upstream.ChainRequest import io.emeraldpay.dshackle.upstream.ChainRequest
import io.emeraldpay.dshackle.upstream.NodeTypeRequest
import io.emeraldpay.dshackle.upstream.UNKNOWN_CLIENT_VERSION
import io.emeraldpay.dshackle.upstream.Upstream import io.emeraldpay.dshackle.upstream.Upstream
import io.emeraldpay.dshackle.upstream.UpstreamSettingsDetector
import io.emeraldpay.dshackle.upstream.rpcclient.ListParams import io.emeraldpay.dshackle.upstream.rpcclient.ListParams
import reactor.core.publisher.Flux import reactor.core.publisher.Flux
class SolanaUpstreamSettingsDetector( class SolanaUpstreamSettingsDetector(
upstream: Upstream, upstream: Upstream,
) : UpstreamSettingsDetector(upstream) { ) : BasicUpstreamSettingsDetector(upstream) {
override fun detectLabels(): Flux<Pair<String, String>> { override fun detectLabels(): Flux<Pair<String, String>> {
return Flux.empty() return Flux.merge(
detectNodeType(),
)
} }
override fun clientVersionRequest(): ChainRequest { override fun clientVersionRequest(): ChainRequest {
@@ -30,4 +35,11 @@ class SolanaUpstreamSettingsDetector(
@JsonProperty("solana-core") @JsonProperty("solana-core")
val version: String, val version: String,
) )
override fun nodeTypeRequest(): NodeTypeRequest = NodeTypeRequest(clientVersionRequest())
override fun clientVersion(node: JsonNode): String? =
node.get("solana-core")?.textValue() ?: UNKNOWN_CLIENT_VERSION
override fun clientType(node: JsonNode): String? = null
} }