fix handling ws + prior rpc connections

This commit is contained in:
Maksim Fomenkov
2022-12-15 12:23:41 +03:00
parent 98e20d08be
commit 627e4be16a
5 changed files with 35 additions and 12 deletions

View File

@@ -93,8 +93,9 @@ abstract class DefaultUpstream(
open fun setStatus(avail: UpstreamAvailability) { open fun setStatus(avail: UpstreamAvailability) {
status.updateAndGet { curr -> status.updateAndGet { curr ->
Status(curr.lag, avail, statusByLag(curr.lag, avail)) Status(curr.lag, avail, statusByLag(curr.lag, avail))
}.also {
statusStream.tryEmitNext(it.status)
} }
statusStream.tryEmitNext(status.get().status)
} }
fun statusByLag(lag: Long, proposed: UpstreamAvailability): UpstreamAvailability { fun statusByLag(lag: Long, proposed: UpstreamAvailability): UpstreamAvailability {
@@ -118,13 +119,12 @@ abstract class DefaultUpstream(
} }
override fun setLag(lag: Long) { override fun setLag(lag: Long) {
if (lag < 0) { lag.coerceAtLeast(0).let { nLag ->
setLag(0)
} else {
status.updateAndGet { curr -> status.updateAndGet { curr ->
Status(lag, curr.avail, statusByLag(lag, curr.avail)) Status(nLag, curr.avail, statusByLag(nLag, curr.avail))
}.also {
statusStream.tryEmitNext(it.status)
} }
statusStream.tryEmitNext(status.get().status)
} }
} }

View File

@@ -61,7 +61,7 @@ open class DefaultEthereumHead(
BlockContainer.fromEthereumJson(it.getResult(), upstreamId) BlockContainer.fromEthereumJson(it.getResult(), upstreamId)
} }
.onErrorResume { err -> .onErrorResume { err ->
log.error("Failed to fetch latest block: ${err.message}") log.error("Failed to fetch latest block: ${err.message} $upstreamId", err)
Mono.empty() Mono.empty()
} }
} }

View File

@@ -11,6 +11,7 @@ import io.emeraldpay.dshackle.upstream.ethereum.EthereumRpcHead
import io.emeraldpay.dshackle.upstream.ethereum.EthereumWsFactory import io.emeraldpay.dshackle.upstream.ethereum.EthereumWsFactory
import io.emeraldpay.dshackle.upstream.ethereum.EthereumWsHead import io.emeraldpay.dshackle.upstream.ethereum.EthereumWsHead
import io.emeraldpay.dshackle.upstream.ethereum.WsConnection import io.emeraldpay.dshackle.upstream.ethereum.WsConnection
import io.emeraldpay.dshackle.upstream.forkchoice.AlwaysForkChoice
import io.emeraldpay.dshackle.upstream.forkchoice.ForkChoice import io.emeraldpay.dshackle.upstream.forkchoice.ForkChoice
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
@@ -35,9 +36,9 @@ class EthereumRpcConnector(
if (wsFactory != null) { if (wsFactory != null) {
// do not set upstream to the WS, since it doesn't control the RPC upstream // do not set upstream to the WS, since it doesn't control the RPC upstream
conn = wsFactory.create(null, null) conn = wsFactory.create(null, null)
val wsHead = EthereumWsHead(conn, id, forkChoice, blockValidator) val wsHead = EthereumWsHead(conn, id, AlwaysForkChoice(), blockValidator)
// receive bew blocks through WebSockets, but also periodically verify with RPC in case if WS failed // receive bew blocks through WebSockets, but also periodically verify with RPC in case if WS failed
val rpcHead = EthereumRpcHead(directReader, forkChoice, id, blockValidator, Duration.ofSeconds(60)) val rpcHead = EthereumRpcHead(directReader, AlwaysForkChoice(), id, blockValidator, Duration.ofSeconds(30))
head = MergedHead(listOf(rpcHead, wsHead), forkChoice, "Merged for $id") head = MergedHead(listOf(rpcHead, wsHead), forkChoice, "Merged for $id")
} else { } else {
conn = null conn = null
@@ -53,10 +54,10 @@ class EthereumRpcConnector(
} }
override fun start() { override fun start() {
conn?.connect()
if (head is Lifecycle) { if (head is Lifecycle) {
head.start() head.start()
} }
conn?.connect()
} }
override fun isRunning(): Boolean { override fun isRunning(): Boolean {

View File

@@ -136,8 +136,8 @@ open class EthereumPosMultiStream(
} }
} }
} }
}.apply { }.also {
onHeadUpdated(this) onHeadUpdated(it)
} }
} }

View File

@@ -0,0 +1,22 @@
package io.emeraldpay.dshackle.upstream.forkchoice
import io.emeraldpay.dshackle.data.BlockContainer
import java.util.concurrent.atomic.AtomicReference
class AlwaysForkChoice : ForkChoice {
private val head = AtomicReference<BlockContainer>(null)
override fun getHead(): BlockContainer? = head.get()
override fun filter(block: BlockContainer): Boolean =
head.get()?.let { it.hash != block.hash } ?: true
override fun choose(block: BlockContainer): ForkChoice.ChoiceResult =
head.updateAndGet { block }.let {
if (it.hash == block.hash) {
ForkChoice.ChoiceResult.Updated(it)
} else {
ForkChoice.ChoiceResult.Same(it)
}
}
}