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/
out/
./dshackle.yaml
dshackle.yaml
./upstream.yaml
testsetup/
.idea/

View File

@@ -11,6 +11,7 @@ import reactor.core.publisher.Mono
const val UNKNOWN_CLIENT_VERSION = "unknown"
typealias UpstreamSettingsDetectorBuilder = (Chain, Upstream) -> UpstreamSettingsDetector?
abstract class UpstreamSettingsDetector(
private val upstream: Upstream,
) {
@@ -34,10 +35,12 @@ abstract class UpstreamSettingsDetector(
protected abstract fun parseClientVersion(data: ByteArray): String
}
abstract class BasicEthUpstreamSettingsDetector(
abstract class BasicUpstreamSettingsDetector(
private val upstream: Upstream,
) : UpstreamSettingsDetector(upstream) {
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>?> {
val nodeTypeRequest = nodeTypeRequest()
@@ -47,25 +50,30 @@ abstract class BasicEthUpstreamSettingsDetector(
.flatMap(ChainResponse::requireResult)
.map { Global.objectMapper.readValue<JsonNode>(it) }
.flatMapMany { node ->
val mappedNode = nodeTypeRequest.mapper(node)
val labels = mutableListOf<Pair<String, String>>()
if (mappedNode.isTextual) {
clientType(mappedNode.textValue())?.let {
labels.add("client_type" to it)
}
clientVersion(mappedNode.textValue())?.let {
labels.add("client_version" to it)
}
clientType(node)?.let {
labels.add("client_type" to it)
}
clientVersion(node)?.let {
labels.add("client_version" to it)
}
Flux.fromIterable(labels)
}
.onErrorResume {
.onErrorResume { error ->
log.warn("Can't detect the node type of upstream ${upstream.getId()}, reason - {}", error.message)
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 secondSlash = client.indexOf("/", firstSlash + 1)
if (firstSlash == -1 || secondSlash == -1 || secondSlash < firstSlash) {
@@ -74,7 +82,8 @@ abstract class BasicEthUpstreamSettingsDetector(
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("/")
if (firstSlash == -1) {
log.debug("Unknown client type: {}", client)
@@ -82,9 +91,8 @@ abstract class BasicEthUpstreamSettingsDetector(
}
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
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.node.NullNode
import com.fasterxml.jackson.module.kotlin.readValue
import io.emeraldpay.dshackle.Global
import io.emeraldpay.dshackle.upstream.BasicEthUpstreamSettingsDetector
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.rpcclient.RestParams
@@ -18,9 +18,7 @@ class BeaconChainUpstreamSettingsDetector(
override fun nodeTypeRequest(): NodeTypeRequest {
return NodeTypeRequest(
clientVersionRequest(),
) { node ->
node.get("data")?.get("version") ?: NullNode.instance
}
)
}
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 {
return ChainRequest("GET#/eth/v1/node/version", RestParams.emptyParams())
}

View File

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

View File

@@ -2,19 +2,24 @@ package io.emeraldpay.dshackle.upstream.near
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.module.kotlin.readValue
import io.emeraldpay.dshackle.Global
import io.emeraldpay.dshackle.upstream.BasicUpstreamSettingsDetector
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.UpstreamSettingsDetector
import io.emeraldpay.dshackle.upstream.rpcclient.ListParams
import reactor.core.publisher.Flux
class NearUpstreamSettingsDetector(
upstream: Upstream,
) : UpstreamSettingsDetector(upstream) {
) : BasicUpstreamSettingsDetector(upstream) {
override fun detectLabels(): Flux<Pair<String, String>> {
return Flux.empty()
return Flux.merge(
detectNodeType(),
)
}
override fun clientVersionRequest(): ChainRequest {
@@ -36,4 +41,11 @@ class NearUpstreamSettingsDetector(
@JsonProperty("version")
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.JsonProperty
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.module.kotlin.readValue
import io.emeraldpay.dshackle.Global
import io.emeraldpay.dshackle.upstream.BasicUpstreamSettingsDetector
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.UpstreamSettingsDetector
import io.emeraldpay.dshackle.upstream.rpcclient.ListParams
import reactor.core.publisher.Flux
class SolanaUpstreamSettingsDetector(
upstream: Upstream,
) : UpstreamSettingsDetector(upstream) {
) : BasicUpstreamSettingsDetector(upstream) {
override fun detectLabels(): Flux<Pair<String, String>> {
return Flux.empty()
return Flux.merge(
detectNodeType(),
)
}
override fun clientVersionRequest(): ChainRequest {
@@ -30,4 +35,11 @@ class SolanaUpstreamSettingsDetector(
@JsonProperty("solana-core")
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
}