Some tunes (#549)

This commit is contained in:
KirillPamPam
2024-08-27 13:50:42 +04:00
committed by GitHub
parent 68344cecaf
commit 8ac58f58b7
26 changed files with 140 additions and 63 deletions

View File

@@ -190,7 +190,7 @@ jib {
} }
} }
container { container {
jvmFlags = ['-XX:+UseG1GC', '-XX:+ExitOnOutOfMemoryError', '-Xms1024M', '-XX:+UnlockDiagnosticVMOptions', '-XX:GCLockerRetryAllocationCount=10', '--enable-preview'] jvmFlags = ['-XX:+UseG1GC', '-XX:+ExitOnOutOfMemoryError', '-Xms1024M', '-XX:NativeMemoryTracking=summary', '-XX:+UnlockDiagnosticVMOptions', '-XX:GCLockerRetryAllocationCount=10', '--enable-preview']
mainClass = 'io.emeraldpay.dshackle.StarterKt' mainClass = 'io.emeraldpay.dshackle.StarterKt'
args = [] args = []
ports = ['2448', '2449', '8545'] ports = ['2448', '2449', '8545']

View File

@@ -25,6 +25,7 @@ class Defaults {
const val maxMetadataSize = 16384 const val maxMetadataSize = 16384
val timeout: Duration = Duration.ofSeconds(60) val timeout: Duration = Duration.ofSeconds(60)
val timeoutInternal: Duration = timeout.dividedBy(4) val timeoutInternal: Duration = timeout.dividedBy(4)
val internalCallsTimeout = Duration.ofSeconds(3)
val retryConnection: Duration = Duration.ofSeconds(10) val retryConnection: Duration = Duration.ofSeconds(10)
val grpcServerKeepAliveTime: Long = 15 // seconds val grpcServerKeepAliveTime: Long = 15 // seconds
val grpcServerKeepAliveTimeout: Long = 5 val grpcServerKeepAliveTimeout: Long = 5

View File

@@ -12,7 +12,9 @@ import reactor.core.scheduler.Scheduler
import reactor.core.scheduler.Schedulers import reactor.core.scheduler.Schedulers
import java.util.concurrent.Executor import java.util.concurrent.Executor
import java.util.concurrent.ExecutorService import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors import java.util.concurrent.SynchronousQueue
import java.util.concurrent.ThreadPoolExecutor
import java.util.concurrent.TimeUnit
@Configuration @Configuration
open class SchedulersConfig { open class SchedulersConfig {
@@ -79,17 +81,24 @@ open class SchedulersConfig {
} }
private fun makePool(name: String, size: Int, monitoringConfig: MonitoringConfig): ExecutorService { private fun makePool(name: String, size: Int, monitoringConfig: MonitoringConfig): ExecutorService {
val pool = Executors.newFixedThreadPool(size, CustomizableThreadFactory("$name-")) val cachedPool = ThreadPoolExecutor(
size,
size * threadsMultiplier,
60L,
TimeUnit.SECONDS,
SynchronousQueue(),
CustomizableThreadFactory("$name-"),
)
return if (monitoringConfig.enableExtended) { return if (monitoringConfig.enableExtended) {
ExecutorServiceMetrics.monitor( ExecutorServiceMetrics.monitor(
Metrics.globalRegistry, Metrics.globalRegistry,
pool, cachedPool,
name, name,
Tag.of("reactor_scheduler_id", "_"), Tag.of("reactor_scheduler_id", "_"),
) )
} else { } else {
pool cachedPool
} }
} }
} }

View File

@@ -178,11 +178,11 @@ class QuorumRequestReader(
src.onErrorResume { err -> src.onErrorResume { err ->
errorHandler.handle(api, key, err.message) errorHandler.handle(api, key, err.message)
val msgError = "Error during call upstream ${api.getId()} with method ${key.method}" val msgError = "Error during call upstream ${api.getId()} with method ${key.method}, reason - ${err.message}"
if (err is ChainCallUpstreamException) { if (err is ChainCallUpstreamException) {
log.debug(msgError, err) log.debug(msgError)
} else { } else {
log.warn(msgError, err) log.warn(msgError)
} }
// when the call failed with an error we want to notify the quorum because // when the call failed with an error we want to notify the quorum because

View File

@@ -41,7 +41,7 @@ class CompoundReader<K, D> (
.flatMap({ rdr -> .flatMap({ rdr ->
rdr.read(key) rdr.read(key)
.timeout(Defaults.timeoutInternal, Mono.empty()) .timeout(Defaults.timeoutInternal, Mono.empty())
.doOnError { t -> log.warn("Failed to read from $rdr", t) } .doOnError { t -> log.warn("Failed to read from {}, reason - {}", rdr, t.message) }
}, 1,) }, 1,)
.next() .next()
} }

View File

@@ -15,6 +15,7 @@ import java.io.ByteArrayInputStream
import java.security.KeyStore import java.security.KeyStore
import java.security.cert.CertificateFactory import java.security.cert.CertificateFactory
import java.security.cert.X509Certificate import java.security.cert.X509Certificate
import java.time.Duration
import java.util.Base64 import java.util.Base64
import java.util.function.Consumer import java.util.function.Consumer
import java.util.function.Function import java.util.function.Function
@@ -31,7 +32,8 @@ abstract class HttpReader(
init { init {
val connectionProvider = ConnectionProvider.builder("dshackleConnectionPool") val connectionProvider = ConnectionProvider.builder("dshackleConnectionPool")
.maxConnections(1500) .maxConnections(1500)
.pendingAcquireMaxCount(10000) .pendingAcquireMaxCount(1000)
.pendingAcquireTimeout(Duration.ofSeconds(10))
.build() .build()
var build = HttpClient.create(connectionProvider) var build = HttpClient.create(connectionProvider)

View File

@@ -3,6 +3,7 @@ package io.emeraldpay.dshackle.upstream
import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.module.kotlin.readValue import com.fasterxml.jackson.module.kotlin.readValue
import io.emeraldpay.dshackle.Chain import io.emeraldpay.dshackle.Chain
import io.emeraldpay.dshackle.Defaults.Companion.internalCallsTimeout
import io.emeraldpay.dshackle.Global import io.emeraldpay.dshackle.Global
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import reactor.core.publisher.Flux import reactor.core.publisher.Flux
@@ -17,15 +18,25 @@ abstract class UpstreamSettingsDetector(
) { ) {
protected val log = LoggerFactory.getLogger(this::class.java) protected val log = LoggerFactory.getLogger(this::class.java)
abstract fun detectLabels(): Flux<Pair<String, String>> fun detectLabels(): Flux<Pair<String, String>> {
return internalDetectLabels()
.timeout(internalCallsTimeout)
.onErrorResume {
log.warn("Couldn't detect lables of upstream {}, message - {}", upstream.getId(), it.message)
Flux.empty()
}
}
protected abstract fun internalDetectLabels(): Flux<Pair<String, String>>
fun detectClientVersion(): Mono<String> { fun detectClientVersion(): Mono<String> {
return upstream.getIngressReader() return upstream.getIngressReader()
.read(clientVersionRequest()) .read(clientVersionRequest())
.flatMap(ChainResponse::requireResult) .flatMap(ChainResponse::requireResult)
.map(::parseClientVersion) .map(::parseClientVersion)
.timeout(internalCallsTimeout)
.onErrorResume { .onErrorResume {
log.warn("Can't detect the client version of upstream ${upstream.getId()}, reason - {}", it.message) log.warn("Can't detect the client version of upstream {}, reason - {}", upstream.getId(), it.message)
Mono.just(UNKNOWN_CLIENT_VERSION) Mono.just(UNKNOWN_CLIENT_VERSION)
} }
} }

View File

@@ -21,7 +21,7 @@ class BeaconChainUpstreamSettingsDetector(
) )
} }
override fun detectLabels(): Flux<Pair<String, String>> { override fun internalDetectLabels(): Flux<Pair<String, String>> {
return Flux.merge( return Flux.merge(
detectNodeType(), detectNodeType(),
) )

View File

@@ -1,6 +1,7 @@
package io.emeraldpay.dshackle.upstream.cosmos package io.emeraldpay.dshackle.upstream.cosmos
import io.emeraldpay.dshackle.Chain import io.emeraldpay.dshackle.Chain
import io.emeraldpay.dshackle.Defaults
import io.emeraldpay.dshackle.Global import io.emeraldpay.dshackle.Global
import io.emeraldpay.dshackle.upstream.ChainRequest import io.emeraldpay.dshackle.upstream.ChainRequest
import io.emeraldpay.dshackle.upstream.Upstream import io.emeraldpay.dshackle.upstream.Upstream
@@ -31,10 +32,13 @@ class CosmosLowerBoundStateDetector(
} }
override fun internalDetectLowerBound(): Flux<LowerBoundData> { override fun internalDetectLowerBound(): Flux<LowerBoundData> {
return upstream.getIngressReader().read(ChainRequest("status", ListParams())).map { return upstream.getIngressReader()
val resp = Global.objectMapper.readValue(it.getResult(), CosmosStatus::class.java) .read(ChainRequest("status", ListParams()))
LowerBoundData(resp.syncInfo.earliestBlockHeight.toLong(), STATE) .timeout(Defaults.internalCallsTimeout)
}.toFlux() .map {
val resp = Global.objectMapper.readValue(it.getResult(), CosmosStatus::class.java)
LowerBoundData(resp.syncInfo.earliestBlockHeight.toLong(), STATE)
}.toFlux()
} }
override fun types(): Set<LowerBoundType> { override fun types(): Set<LowerBoundType> {

View File

@@ -14,7 +14,7 @@ import reactor.core.publisher.Flux
class CosmosUpstreamSettingsDetector( class CosmosUpstreamSettingsDetector(
upstream: Upstream, upstream: Upstream,
) : BasicUpstreamSettingsDetector(upstream) { ) : BasicUpstreamSettingsDetector(upstream) {
override fun detectLabels(): Flux<Pair<String, String>> { override fun internalDetectLabels(): Flux<Pair<String, String>> {
return Flux.merge( return Flux.merge(
detectNodeType(), detectNodeType(),
) )

View File

@@ -2,6 +2,7 @@ package io.emeraldpay.dshackle.upstream.ethereum
import com.fasterxml.jackson.module.kotlin.readValue import com.fasterxml.jackson.module.kotlin.readValue
import io.emeraldpay.dshackle.Chain import io.emeraldpay.dshackle.Chain
import io.emeraldpay.dshackle.Defaults
import io.emeraldpay.dshackle.Global import io.emeraldpay.dshackle.Global
import io.emeraldpay.dshackle.upstream.ChainRequest import io.emeraldpay.dshackle.upstream.ChainRequest
import io.emeraldpay.dshackle.upstream.Upstream import io.emeraldpay.dshackle.upstream.Upstream
@@ -72,6 +73,7 @@ class EthereumFinalizationDetector : FinalizationDetector {
upstream upstream
.getIngressReader() .getIngressReader()
.read(req) .read(req)
.timeout(Defaults.internalCallsTimeout)
.flatMap { .flatMap {
it.requireResult().flatMap { result -> it.requireResult().flatMap { result ->
val block = Global.objectMapper.readValue<BlockJson<TransactionRefJson>>(result) val block = Global.objectMapper.readValue<BlockJson<TransactionRefJson>>(result)

View File

@@ -1,5 +1,6 @@
package io.emeraldpay.dshackle.upstream.ethereum package io.emeraldpay.dshackle.upstream.ethereum
import io.emeraldpay.dshackle.Defaults
import io.emeraldpay.dshackle.upstream.ChainCallError import io.emeraldpay.dshackle.upstream.ChainCallError
import io.emeraldpay.dshackle.upstream.ChainCallUpstreamException import io.emeraldpay.dshackle.upstream.ChainCallUpstreamException
import io.emeraldpay.dshackle.upstream.ChainRequest import io.emeraldpay.dshackle.upstream.ChainRequest
@@ -45,6 +46,7 @@ class EthereumLowerBoundBlockDetector(
ListParams(block.toHex(), false), ListParams(block.toHex(), false),
), ),
) )
.timeout(Defaults.internalCallsTimeout)
.doOnNext { .doOnNext {
if (it.hasResult() && it.getResult().contentEquals("null".toByteArray())) { if (it.hasResult() && it.getResult().contentEquals("null".toByteArray())) {
throw IllegalStateException(NO_BLOCK_DATA) throw IllegalStateException(NO_BLOCK_DATA)

View File

@@ -1,5 +1,6 @@
package io.emeraldpay.dshackle.upstream.ethereum package io.emeraldpay.dshackle.upstream.ethereum
import io.emeraldpay.dshackle.Defaults
import io.emeraldpay.dshackle.upstream.ChainRequest import io.emeraldpay.dshackle.upstream.ChainRequest
import io.emeraldpay.dshackle.upstream.Upstream import io.emeraldpay.dshackle.upstream.Upstream
import io.emeraldpay.dshackle.upstream.lowerbound.LowerBoundData import io.emeraldpay.dshackle.upstream.lowerbound.LowerBoundData
@@ -39,6 +40,7 @@ class EthereumLowerBoundLogsDetector(
), ),
), ),
) )
.timeout(Defaults.internalCallsTimeout)
.doOnNext { .doOnNext {
if (it.hasResult() && (it.getResult().contentEquals("null".toByteArray()) || it.getResult().contentEquals("[]".toByteArray()))) { if (it.hasResult() && (it.getResult().contentEquals("null".toByteArray()) || it.getResult().contentEquals("[]".toByteArray()))) {
throw IllegalStateException(NO_LOGS_DATA) throw IllegalStateException(NO_LOGS_DATA)

View File

@@ -1,5 +1,6 @@
package io.emeraldpay.dshackle.upstream.ethereum package io.emeraldpay.dshackle.upstream.ethereum
import io.emeraldpay.dshackle.Defaults
import io.emeraldpay.dshackle.Global import io.emeraldpay.dshackle.Global
import io.emeraldpay.dshackle.upstream.ChainRequest import io.emeraldpay.dshackle.upstream.ChainRequest
import io.emeraldpay.dshackle.upstream.ChainResponse import io.emeraldpay.dshackle.upstream.ChainResponse
@@ -60,7 +61,7 @@ class EthereumLowerBoundStateDetector(
"eth_getBalance", "eth_getBalance",
ListParams(ZERO_ADDRESS, block.toHex()), ListParams(ZERO_ADDRESS, block.toHex()),
), ),
) ).timeout(Defaults.internalCallsTimeout)
}.doOnNext { }.doOnNext {
if (it.hasResult() && it.getResult().contentEquals(Global.nullValue)) { if (it.hasResult() && it.getResult().contentEquals(Global.nullValue)) {
throw IllegalStateException("No state data") throw IllegalStateException("No state data")

View File

@@ -1,5 +1,6 @@
package io.emeraldpay.dshackle.upstream.ethereum package io.emeraldpay.dshackle.upstream.ethereum
import io.emeraldpay.dshackle.Defaults
import io.emeraldpay.dshackle.data.BlockContainer import io.emeraldpay.dshackle.data.BlockContainer
import io.emeraldpay.dshackle.upstream.ChainRequest import io.emeraldpay.dshackle.upstream.ChainRequest
import io.emeraldpay.dshackle.upstream.Upstream import io.emeraldpay.dshackle.upstream.Upstream
@@ -32,6 +33,7 @@ class EthereumLowerBoundTxDetector(
.read( .read(
ChainRequest("eth_getBlockByNumber", ListParams(block.toHex(), false)), ChainRequest("eth_getBlockByNumber", ListParams(block.toHex(), false)),
) )
.timeout(Defaults.internalCallsTimeout)
.doOnNext { .doOnNext {
if (it.hasResult() && it.getResult().contentEquals("null".toByteArray())) { if (it.hasResult() && it.getResult().contentEquals("null".toByteArray())) {
throw IllegalStateException(NO_TX_DATA) throw IllegalStateException(NO_TX_DATA)
@@ -50,6 +52,7 @@ class EthereumLowerBoundTxDetector(
.read( .read(
ChainRequest("eth_getTransactionByHash", ListParams(tx)), ChainRequest("eth_getTransactionByHash", ListParams(tx)),
) )
.timeout(Defaults.internalCallsTimeout)
.doOnNext { .doOnNext {
if (it.hasResult() && it.getResult().contentEquals("null".toByteArray())) { if (it.hasResult() && it.getResult().contentEquals("null".toByteArray())) {
throw IllegalStateException(NO_TX_DATA) throw IllegalStateException(NO_TX_DATA)

View File

@@ -11,7 +11,6 @@ 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
import reactor.core.publisher.Mono import reactor.core.publisher.Mono
import kotlin.text.toBigInteger
const val ZERO_ADDRESS = "0x0000000000000000000000000000000000000000" const val ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"
@@ -21,7 +20,7 @@ class EthereumUpstreamSettingsDetector(
) : BasicEthUpstreamSettingsDetector(_upstream) { ) : BasicEthUpstreamSettingsDetector(_upstream) {
private val blockNumberReader = EthereumArchiveBlockNumberReader(upstream.getIngressReader()) private val blockNumberReader = EthereumArchiveBlockNumberReader(upstream.getIngressReader())
override fun detectLabels(): Flux<Pair<String, String>> { override fun internalDetectLabels(): Flux<Pair<String, String>> {
return Flux.merge( return Flux.merge(
detectNodeType(), detectNodeType(),
detectArchiveNode(), detectArchiveNode(),

View File

@@ -1,5 +1,6 @@
package io.emeraldpay.dshackle.upstream.generic package io.emeraldpay.dshackle.upstream.generic
import io.emeraldpay.dshackle.Defaults.Companion.internalCallsTimeout
import io.emeraldpay.dshackle.foundation.ChainOptions import io.emeraldpay.dshackle.foundation.ChainOptions
import io.emeraldpay.dshackle.upstream.SingleValidator import io.emeraldpay.dshackle.upstream.SingleValidator
import io.emeraldpay.dshackle.upstream.Upstream import io.emeraldpay.dshackle.upstream.Upstream
@@ -21,8 +22,9 @@ class AggregatedUpstreamValidator(
) { a -> a.map { it as UpstreamAvailability } } ) { a -> a.map { it as UpstreamAvailability } }
.map(::resolve) .map(::resolve)
.defaultIfEmpty(UpstreamAvailability.OK) // upstream is OK on case there are no validators .defaultIfEmpty(UpstreamAvailability.OK) // upstream is OK on case there are no validators
.timeout(internalCallsTimeout)
.onErrorResume { .onErrorResume {
log.error("Error during upstream validation for ${upstream.getId()}", it) log.error("Error during upstream validation for {}, reason - {}", upstream.getId(), it.message)
Mono.just(UpstreamAvailability.UNAVAILABLE) Mono.just(UpstreamAvailability.UNAVAILABLE)
} }
} }
@@ -33,13 +35,16 @@ class AggregatedUpstreamValidator(
) { a -> a.map { it as ValidateUpstreamSettingsResult } } ) { a -> a.map { it as ValidateUpstreamSettingsResult } }
.map(::resolve) .map(::resolve)
.defaultIfEmpty(ValidateUpstreamSettingsResult.UPSTREAM_VALID) .defaultIfEmpty(ValidateUpstreamSettingsResult.UPSTREAM_VALID)
.timeout(internalCallsTimeout)
.onErrorResume { .onErrorResume {
log.error("Error during upstream validation for ${upstream.getId()}", it) log.error("Error during upstream validation for {}, reason - {}", upstream.getId(), it.message)
Mono.just(ValidateUpstreamSettingsResult.UPSTREAM_FATAL_SETTINGS_ERROR) Mono.just(ValidateUpstreamSettingsResult.UPSTREAM_FATAL_SETTINGS_ERROR)
} }
} }
override fun validateUpstreamSettingsOnStartup(): ValidateUpstreamSettingsResult { override fun validateUpstreamSettingsOnStartup(): ValidateUpstreamSettingsResult {
return validateUpstreamSettings().block() ?: ValidateUpstreamSettingsResult.UPSTREAM_VALID return runCatching {
validateUpstreamSettings().block(internalCallsTimeout) ?: ValidateUpstreamSettingsResult.UPSTREAM_VALID
}.getOrDefault(ValidateUpstreamSettingsResult.UPSTREAM_SETTINGS_ERROR)
} }
} }

View File

@@ -46,12 +46,15 @@ class GenericRpcHead(
override fun start() { override fun start() {
super.start() super.start()
refreshSubscription?.dispose() refreshSubscription?.dispose()
val base = Flux.interval(interval) val base = Flux.interval(interval)
.onBackpressureDrop()
.publishOn(headScheduler) .publishOn(headScheduler)
.filter { !isSyncing } .filter { !isSyncing }
.flatMap { .concatMap {
getLatestBlock(api) getLatestBlock(api)
} }
refreshSubscription = super.follow(base) refreshSubscription = super.follow(base)
} }

View File

@@ -1,6 +1,7 @@
package io.emeraldpay.dshackle.upstream.generic package io.emeraldpay.dshackle.upstream.generic
import io.emeraldpay.dshackle.Chain import io.emeraldpay.dshackle.Chain
import io.emeraldpay.dshackle.Defaults
import io.emeraldpay.dshackle.config.ChainsConfig import io.emeraldpay.dshackle.config.ChainsConfig
import io.emeraldpay.dshackle.config.UpstreamsConfig import io.emeraldpay.dshackle.config.UpstreamsConfig
import io.emeraldpay.dshackle.config.UpstreamsConfig.Labels import io.emeraldpay.dshackle.config.UpstreamsConfig.Labels
@@ -35,10 +36,13 @@ import io.emeraldpay.dshackle.upstream.lowerbound.LowerBoundData
import io.emeraldpay.dshackle.upstream.lowerbound.LowerBoundServiceBuilder import io.emeraldpay.dshackle.upstream.lowerbound.LowerBoundServiceBuilder
import io.emeraldpay.dshackle.upstream.lowerbound.LowerBoundType import io.emeraldpay.dshackle.upstream.lowerbound.LowerBoundType
import org.springframework.context.Lifecycle import org.springframework.context.Lifecycle
import org.springframework.scheduling.concurrent.CustomizableThreadFactory
import reactor.core.Disposable import reactor.core.Disposable
import reactor.core.publisher.Flux import reactor.core.publisher.Flux
import reactor.core.publisher.Sinks import reactor.core.publisher.Sinks
import reactor.core.scheduler.Schedulers
import java.time.Duration import java.time.Duration
import java.util.concurrent.Executors
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicReference import java.util.concurrent.atomic.AtomicReference
import java.util.function.Supplier import java.util.function.Supplier
@@ -192,6 +196,7 @@ open class GenericUpstream(
}, },
headLivenessState.asFlux(), headLivenessState.asFlux(),
) )
.subscribeOn(upstreamSettingsScheduler)
.distinctUntilChanged() .distinctUntilChanged()
.subscribe { .subscribe {
when (it) { when (it) {
@@ -238,29 +243,35 @@ open class GenericUpstream(
clientVersion.set(it) clientVersion.set(it)
}, },
) )
.subscribeOn(settingsScheduler)
}.subscribe() }.subscribe()
} }
private fun detectRpcModules(config: UpstreamsConfig.Upstream<*>, buildMethods: (UpstreamsConfig.Upstream<*>, Chain) -> CallMethods) { private fun detectRpcModules(config: UpstreamsConfig.Upstream<*>, buildMethods: (UpstreamsConfig.Upstream<*>, Chain) -> CallMethods) {
val rpcDetector = rpcModulesDetector?.detectRpcModules()?.block() ?: HashMap<String, String>() try {
log.info("Upstream rpc detector for ${getId()} returned $rpcDetector ") val rpcDetector = rpcModulesDetector?.detectRpcModules()?.block(Defaults.internalCallsTimeout)
if (rpcDetector.size != 0) { ?: HashMap<String, String>()
var changed = false log.info("Upstream rpc detector for ${getId()} returned $rpcDetector ")
for ((group, _) in rpcDetector) { if (rpcDetector.size != 0) {
if (group == "trace" || group == "debug" || group == "filter") { var changed = false
if (config.methodGroups == null) { for ((group, _) in rpcDetector) {
config.methodGroups = UpstreamsConfig.MethodGroups(setOf("filter"), setOf()) if (group == "trace" || group == "debug" || group == "filter") {
} else { if (config.methodGroups == null) {
val disabled = config.methodGroups!!.disabled config.methodGroups = UpstreamsConfig.MethodGroups(setOf("filter"), setOf())
val enabled = config.methodGroups!!.enabled } else {
if (!disabled.contains(group) && !enabled.contains(group)) { val disabled = config.methodGroups!!.disabled
config.methodGroups!!.enabled = enabled.plus(group) val enabled = config.methodGroups!!.enabled
changed = true if (!disabled.contains(group) && !enabled.contains(group)) {
config.methodGroups!!.enabled = enabled.plus(group)
changed = true
}
} }
} }
} }
if (changed) updateMethods(buildMethods(config, getChain()))
} }
if (changed) updateMethods(buildMethods(config, getChain())) } catch (e: RuntimeException) {
log.error("Couldn't detect rpc modules of upstream {} due to error {}", getId(), e.message)
} }
} }
@@ -331,14 +342,17 @@ open class GenericUpstream(
private fun detectFinalization() { private fun detectFinalization() {
finalizationDetectorSubscription = finalizationDetectorSubscription =
finalizationDetector.detectFinalization(this, chainConfig.expectedBlockTime, getChain()).subscribe { finalizationDetector.detectFinalization(this, chainConfig.expectedBlockTime, getChain())
sendUpstreamStateEvent(UPDATED) .subscribeOn(finalizationScheduler)
} .subscribe {
sendUpstreamStateEvent(UPDATED)
}
} }
private fun detectLowerBlock() { private fun detectLowerBlock() {
lowerBlockDetectorSubscription = lowerBlockDetectorSubscription =
lowerBoundService.detectLowerBounds() lowerBoundService.detectLowerBounds()
.subscribeOn(lowerScheduler)
.subscribe { .subscribe {
sendUpstreamStateEvent(UPDATED) sendUpstreamStateEvent(UPDATED)
} }
@@ -359,4 +373,15 @@ open class GenericUpstream(
} }
fun isValid(): Boolean = isUpstreamValid.get() fun isValid(): Boolean = isUpstreamValid.get()
companion object {
private val upstreamSettingsScheduler =
Schedulers.fromExecutor(Executors.newFixedThreadPool(4, CustomizableThreadFactory("upstreamSettings-")))
private val finalizationScheduler =
Schedulers.fromExecutor(Executors.newFixedThreadPool(4, CustomizableThreadFactory("finalization-")))
private val settingsScheduler =
Schedulers.fromExecutor(Executors.newFixedThreadPool(4, CustomizableThreadFactory("settings-")))
private val lowerScheduler =
Schedulers.fromExecutor(Executors.newFixedThreadPool(4, CustomizableThreadFactory("lowerBound-")))
}
} }

View File

@@ -1,5 +1,6 @@
package io.emeraldpay.dshackle.upstream.near package io.emeraldpay.dshackle.upstream.near
import io.emeraldpay.dshackle.Defaults
import io.emeraldpay.dshackle.Global import io.emeraldpay.dshackle.Global
import io.emeraldpay.dshackle.upstream.ChainRequest import io.emeraldpay.dshackle.upstream.ChainRequest
import io.emeraldpay.dshackle.upstream.Upstream import io.emeraldpay.dshackle.upstream.Upstream
@@ -18,17 +19,20 @@ class NearLowerBoundStateDetector(
} }
override fun internalDetectLowerBound(): Flux<LowerBoundData> { override fun internalDetectLowerBound(): Flux<LowerBoundData> {
return upstream.getIngressReader().read(ChainRequest("status", ListParams())).map { return upstream.getIngressReader()
val resp = Global.objectMapper.readValue(it.getResult(), NearStatus::class.java) .read(ChainRequest("status", ListParams()))
resp.syncInfo.earliestHeight .timeout(Defaults.internalCallsTimeout)
}.flatMapMany { .map {
Flux.fromIterable( val resp = Global.objectMapper.readValue(it.getResult(), NearStatus::class.java)
listOf( resp.syncInfo.earliestHeight
LowerBoundData(it, LowerBoundType.STATE), }.flatMapMany {
LowerBoundData(it, LowerBoundType.BLOCK), Flux.fromIterable(
), listOf(
) LowerBoundData(it, LowerBoundType.STATE),
} LowerBoundData(it, LowerBoundType.BLOCK),
),
)
}
} }
override fun types(): Set<LowerBoundType> { override fun types(): Set<LowerBoundType> {

View File

@@ -16,7 +16,7 @@ import reactor.core.publisher.Flux
class NearUpstreamSettingsDetector( class NearUpstreamSettingsDetector(
upstream: Upstream, upstream: Upstream,
) : BasicUpstreamSettingsDetector(upstream) { ) : BasicUpstreamSettingsDetector(upstream) {
override fun detectLabels(): Flux<Pair<String, String>> { override fun internalDetectLabels(): Flux<Pair<String, String>> {
return Flux.merge( return Flux.merge(
detectNodeType(), detectNodeType(),
) )

View File

@@ -1,5 +1,6 @@
package io.emeraldpay.dshackle.upstream.polkadot package io.emeraldpay.dshackle.upstream.polkadot
import io.emeraldpay.dshackle.Defaults
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.Upstream import io.emeraldpay.dshackle.upstream.Upstream
@@ -34,6 +35,7 @@ class PolkadotLowerBoundStateDetector(
ListParams(block.toHex()), // in polkadot state methods work only with hash ListParams(block.toHex()), // in polkadot state methods work only with hash
), ),
) )
.timeout(Defaults.internalCallsTimeout)
.flatMap(ChainResponse::requireResult) .flatMap(ChainResponse::requireResult)
.map { .map {
String(it, 1, it.size - 2) String(it, 1, it.size - 2)
@@ -44,7 +46,7 @@ class PolkadotLowerBoundStateDetector(
"state_getMetadata", "state_getMetadata",
ListParams(it), ListParams(it),
), ),
) ).timeout(Defaults.internalCallsTimeout)
} }
} }
} }

View File

@@ -1,5 +1,6 @@
package io.emeraldpay.dshackle.upstream.solana package io.emeraldpay.dshackle.upstream.solana
import io.emeraldpay.dshackle.Defaults
import io.emeraldpay.dshackle.Global import io.emeraldpay.dshackle.Global
import io.emeraldpay.dshackle.upstream.ChainRequest import io.emeraldpay.dshackle.upstream.ChainRequest
import io.emeraldpay.dshackle.upstream.ChainResponse import io.emeraldpay.dshackle.upstream.ChainResponse
@@ -28,7 +29,7 @@ class SolanaLowerBoundSlotDetector(
.flatMap { .flatMap {
it.read( it.read(
ChainRequest("getFirstAvailableBlock", ListParams()), // in case of solana we talk about the slot of the lowest confirmed block ChainRequest("getFirstAvailableBlock", ListParams()), // in case of solana we talk about the slot of the lowest confirmed block
) ).timeout(Defaults.internalCallsTimeout)
} }
.flatMap(ChainResponse::requireResult) .flatMap(ChainResponse::requireResult)
.map { .map {
@@ -53,6 +54,7 @@ class SolanaLowerBoundSlotDetector(
), ),
), ),
) )
.timeout(Defaults.internalCallsTimeout)
.flatMap(ChainResponse::requireResult) .flatMap(ChainResponse::requireResult)
.flatMapMany { blockData -> .flatMapMany { blockData ->
val block = Global.objectMapper.readValue(blockData, SolanaBlock::class.java) val block = Global.objectMapper.readValue(blockData, SolanaBlock::class.java)

View File

@@ -16,7 +16,7 @@ import reactor.core.publisher.Flux
class SolanaUpstreamSettingsDetector( class SolanaUpstreamSettingsDetector(
upstream: Upstream, upstream: Upstream,
) : BasicUpstreamSettingsDetector(upstream) { ) : BasicUpstreamSettingsDetector(upstream) {
override fun detectLabels(): Flux<Pair<String, String>> { override fun internalDetectLabels(): Flux<Pair<String, String>> {
return Flux.merge( return Flux.merge(
detectNodeType(), detectNodeType(),
) )

View File

@@ -40,7 +40,7 @@ class EthereumUpstreamSettingsDetectorSpec extends Specification {
def detector = new EthereumUpstreamSettingsDetector(up, Chain.ETHEREUM__MAINNET) def detector = new EthereumUpstreamSettingsDetector(up, Chain.ETHEREUM__MAINNET)
when: when:
def act = detector.detectLabels() def act = detector.internalDetectLabels()
then: then:
StepVerifier.create(act) StepVerifier.create(act)
.expectNext( .expectNext(
@@ -72,7 +72,7 @@ class EthereumUpstreamSettingsDetectorSpec extends Specification {
def detector = new EthereumUpstreamSettingsDetector(up, Chain.ETHEREUM__MAINNET) def detector = new EthereumUpstreamSettingsDetector(up, Chain.ETHEREUM__MAINNET)
when: when:
def act = detector.detectLabels() def act = detector.internalDetectLabels()
then: then:
StepVerifier.create(act) StepVerifier.create(act)
.expectNext( .expectNext(
@@ -113,7 +113,7 @@ class EthereumUpstreamSettingsDetectorSpec extends Specification {
} }
def detector = new EthereumUpstreamSettingsDetector(up, Chain.ETHEREUM__MAINNET) def detector = new EthereumUpstreamSettingsDetector(up, Chain.ETHEREUM__MAINNET)
when: when:
def act = detector.detectLabels() def act = detector.internalDetectLabels()
then: then:
StepVerifier.create(act) StepVerifier.create(act)
.expectNext(new Pair<String, String>("archive", "false")) .expectNext(new Pair<String, String>("archive", "false"))

View File

@@ -444,10 +444,10 @@ class GenericWsHeadTest {
StepVerifier.create(wsHead.headLiveness()) StepVerifier.create(wsHead.headLiveness())
.expectNext(HeadLivenessState.FATAL_ERROR) .expectNext(HeadLivenessState.FATAL_ERROR)
.thenCancel() .thenCancel()
.verify(Duration.ofSeconds(1)) .verify(Duration.ofSeconds(2))
} }
.thenCancel() .thenCancel()
.verify(Duration.ofSeconds(1)) .verify(Duration.ofSeconds(3))
verify(connection, times(2)).callRpc(ChainRequest("eth_chainId", ListParams())) verify(connection, times(2)).callRpc(ChainRequest("eth_chainId", ListParams()))
verify(connection, times(2)).callRpc(ChainRequest("net_version", ListParams())) verify(connection, times(2)).callRpc(ChainRequest("net_version", ListParams()))