Turn off subs if conn type is rpc (#454)

This commit is contained in:
KirillPamPam
2024-04-18 12:33:26 +04:00
committed by GitHub
parent c377083e75
commit d76486b3fd
5 changed files with 80 additions and 60 deletions

View File

@@ -1,59 +1,14 @@
package io.emeraldpay.dshackle.upstream.ethereum
import io.emeraldpay.dshackle.ThrottledLogger
import io.emeraldpay.dshackle.upstream.Head
import org.slf4j.LoggerFactory
import reactor.core.publisher.Flux
import reactor.core.scheduler.Scheduler
import java.time.Duration
class HeadLivenessValidator(
private val head: Head,
private val expectedBlockTime: Duration,
private val scheduler: Scheduler,
private val upstreamId: String,
) {
companion object {
const val CHECKED_BLOCKS_UNTIL_LIVE = 3
private val log = LoggerFactory.getLogger(HeadLivenessValidator::class.java)
}
interface HeadLivenessValidator {
fun getFlux(): Flux<Boolean>
}
fun getFlux(): Flux<Boolean> {
val headLiveness = head.headLiveness()
// first we have moving window of 2 blocks and check that they are consecutive ones
val headFlux = head.getFlux().map { it.height }.buffer(2, 1).map {
it.last() - it.first() == 1L
}.scan(Pair(0, true)) { acc, value ->
// then we accumulate consecutive true events, false resets counter
if (value) {
Pair(acc.first + 1, true)
} else {
if (log.isDebugEnabled) {
log.debug("non consecutive blocks in head for $upstreamId")
} else {
ThrottledLogger.log(log, "non consecutive blocks in head for $upstreamId")
}
Pair(0, false)
}
}.flatMap { (count, value) ->
// we emit when we have false or checked CHECKED_BLOCKS_UNTIL_LIVE blocks
// CHECKED_BLOCKS_UNTIL_LIVE blocks == (CHECKED_BLOCKS_UNTIL_LIVE - 1) consecutive true
when {
count >= (CHECKED_BLOCKS_UNTIL_LIVE - 1) -> Flux.just(true)
!value -> Flux.just(false)
else -> Flux.empty()
}
}.timeout(
expectedBlockTime.multipliedBy(CHECKED_BLOCKS_UNTIL_LIVE.toLong() * 2),
Flux.just(false).doOnNext {
if (log.isDebugEnabled) {
log.debug("head liveness check broken with timeout in $upstreamId")
} else {
ThrottledLogger.log(log, "head liveness check broken with timeout in $upstreamId")
}
},
).repeat().subscribeOn(scheduler)
class NoHeadLivenessValidator : HeadLivenessValidator {
return Flux.merge(headFlux, headLiveness)
override fun getFlux(): Flux<Boolean> {
return Flux.just(false)
}
}

View File

@@ -0,0 +1,59 @@
package io.emeraldpay.dshackle.upstream.ethereum
import io.emeraldpay.dshackle.ThrottledLogger
import io.emeraldpay.dshackle.upstream.Head
import org.slf4j.LoggerFactory
import reactor.core.publisher.Flux
import reactor.core.scheduler.Scheduler
import java.time.Duration
class HeadLivenessValidatorImpl(
private val head: Head,
private val expectedBlockTime: Duration,
private val scheduler: Scheduler,
private val upstreamId: String,
) : HeadLivenessValidator {
companion object {
const val CHECKED_BLOCKS_UNTIL_LIVE = 3
private val log = LoggerFactory.getLogger(HeadLivenessValidatorImpl::class.java)
}
override fun getFlux(): Flux<Boolean> {
val headLiveness = head.headLiveness()
// first we have moving window of 2 blocks and check that they are consecutive ones
val headFlux = head.getFlux().map { it.height }.buffer(2, 1).map {
it.last() - it.first() == 1L
}.scan(Pair(0, true)) { acc, value ->
// then we accumulate consecutive true events, false resets counter
if (value) {
Pair(acc.first + 1, true)
} else {
if (log.isDebugEnabled) {
log.debug("non consecutive blocks in head for $upstreamId")
} else {
ThrottledLogger.log(log, "non consecutive blocks in head for $upstreamId")
}
Pair(0, false)
}
}.flatMap { (count, value) ->
// we emit when we have false or checked CHECKED_BLOCKS_UNTIL_LIVE blocks
// CHECKED_BLOCKS_UNTIL_LIVE blocks == (CHECKED_BLOCKS_UNTIL_LIVE - 1) consecutive true
when {
count >= (CHECKED_BLOCKS_UNTIL_LIVE - 1) -> Flux.just(true)
!value -> Flux.just(false)
else -> Flux.empty()
}
}.timeout(
expectedBlockTime.multipliedBy(CHECKED_BLOCKS_UNTIL_LIVE.toLong() * 2),
Flux.just(false).doOnNext {
if (log.isDebugEnabled) {
log.debug("head liveness check broken with timeout in $upstreamId")
} else {
ThrottledLogger.log(log, "head liveness check broken with timeout in $upstreamId")
}
},
).repeat().subscribeOn(scheduler)
return Flux.merge(headFlux, headLiveness)
}
}

View File

@@ -13,6 +13,8 @@ import io.emeraldpay.dshackle.upstream.MergedHead
import io.emeraldpay.dshackle.upstream.NoIngressSubscription
import io.emeraldpay.dshackle.upstream.ethereum.GenericWsHead
import io.emeraldpay.dshackle.upstream.ethereum.HeadLivenessValidator
import io.emeraldpay.dshackle.upstream.ethereum.HeadLivenessValidatorImpl
import io.emeraldpay.dshackle.upstream.ethereum.NoHeadLivenessValidator
import io.emeraldpay.dshackle.upstream.ethereum.WsConnectionPool
import io.emeraldpay.dshackle.upstream.ethereum.WsConnectionPoolFactory
import io.emeraldpay.dshackle.upstream.ethereum.WsSubscriptions
@@ -123,7 +125,11 @@ class GenericRpcConnector(
)
}
}
liveness = HeadLivenessValidator(head, expectedBlockTime, headLivenessScheduler, id)
liveness = when (connectorType) {
RPC_ONLY -> NoHeadLivenessValidator()
RPC_REQUESTS_WITH_MIXED_HEAD, RPC_REQUESTS_WITH_WS_HEAD, WS_ONLY -> HeadLivenessValidatorImpl(head, expectedBlockTime, headLivenessScheduler, id)
}
}
override fun setCaches(caches: Caches) {

View File

@@ -6,7 +6,7 @@ import io.emeraldpay.dshackle.upstream.DefaultUpstream
import io.emeraldpay.dshackle.upstream.Head
import io.emeraldpay.dshackle.upstream.IngressSubscription
import io.emeraldpay.dshackle.upstream.ethereum.GenericWsHead
import io.emeraldpay.dshackle.upstream.ethereum.HeadLivenessValidator
import io.emeraldpay.dshackle.upstream.ethereum.HeadLivenessValidatorImpl
import io.emeraldpay.dshackle.upstream.ethereum.WsConnectionPool
import io.emeraldpay.dshackle.upstream.ethereum.WsConnectionPoolFactory
import io.emeraldpay.dshackle.upstream.ethereum.WsSubscriptionsImpl
@@ -32,7 +32,7 @@ class GenericWsConnector(
private val reader: ChainReader
private val head: GenericWsHead
private val subscriptions: IngressSubscription
private val liveness: HeadLivenessValidator
private val liveness: HeadLivenessValidatorImpl
init {
pool = wsFactory.create(upstream)
reader = JsonRpcWsClient(pool)
@@ -48,7 +48,7 @@ class GenericWsConnector(
chainSpecific,
expectedBlockTime,
)
liveness = HeadLivenessValidator(head, expectedBlockTime, headLivenessScheduler, upstream.getId())
liveness = HeadLivenessValidatorImpl(head, expectedBlockTime, headLivenessScheduler, upstream.getId())
subscriptions = chainSpecific.makeIngressSubscription(wsSubscriptions)
}