Skip to content

Commit

Permalink
Node client_type & client_version not parsed for non-eth chains (#467)
Browse files Browse the repository at this point in the history
* Fix labels fill

* return null in case of unknown client type
  • Loading branch information
tonatoz authored May 7, 2024
1 parent 5f62838 commit 65c383a
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 33 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
build/
out/
./dshackle.yaml
dshackle.yaml
./upstream.yaml
testsetup/
.idea/
Expand Down
2 changes: 1 addition & 1 deletion emerald-grpc
Original file line number Diff line number Diff line change
Expand Up @@ -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,
) {
Expand All @@ -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()
Expand All @@ -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) {
Expand All @@ -74,17 +82,17 @@ 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)
return null
}
return client.substring(0, firstSlash).lowercase()
}

data class NodeTypeRequest(
val request: ChainRequest,
val mapper: (JsonNode) -> JsonNode,
)
}

data class NodeTypeRequest(
val request: ChainRequest,
)
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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>> {
Expand All @@ -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())
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -24,6 +26,10 @@ class EthereumUpstreamSettingsDetector(
)
}

override fun mapping(node: JsonNode): String {
return node.asText()
}

override fun clientVersionRequest(): ChainRequest {
return ChainRequest("web3_clientVersion", ListParams())
}
Expand Down Expand Up @@ -54,9 +60,5 @@ class EthereumUpstreamSettingsDetector(
).flatMap(ChainResponse::requireResult)
}

override fun nodeTypeRequest(): NodeTypeRequest {
return NodeTypeRequest(
clientVersionRequest(),
) { node -> node }
}
override fun nodeTypeRequest(): NodeTypeRequest = NodeTypeRequest(clientVersionRequest())
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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
}

0 comments on commit 65c383a

Please sign in to comment.