solution: check current height on connect
This commit is contained in:
@@ -15,9 +15,48 @@
|
|||||||
*/
|
*/
|
||||||
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.reader.Reader
|
||||||
import io.emeraldpay.dshackle.upstream.AbstractHead
|
import io.emeraldpay.dshackle.upstream.AbstractHead
|
||||||
import io.emeraldpay.dshackle.upstream.Head
|
import io.emeraldpay.dshackle.upstream.Head
|
||||||
|
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
||||||
|
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
|
||||||
|
import io.emeraldpay.etherjar.hex.HexQuantity
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
import reactor.core.publisher.Mono
|
||||||
|
|
||||||
open class DefaultEthereumHead : Head, AbstractHead() {
|
open class DefaultEthereumHead : Head, AbstractHead() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val log = LoggerFactory.getLogger(DefaultEthereumHead::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getLatestBlock(api: Reader<JsonRpcRequest, JsonRpcResponse>): Mono<BlockContainer> {
|
||||||
|
return api.read(JsonRpcRequest("eth_blockNumber", emptyList()))
|
||||||
|
.subscribeOn(EthereumRpcHead.scheduler)
|
||||||
|
.timeout(Defaults.timeout, Mono.error(Exception("Block number not received")))
|
||||||
|
.flatMap {
|
||||||
|
if (it.error != null) {
|
||||||
|
Mono.error(it.error.asException(null))
|
||||||
|
} else {
|
||||||
|
val value = it.getResultAsProcessedString()
|
||||||
|
Mono.just(HexQuantity.from(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.flatMap {
|
||||||
|
//fetching by Block Height here, critical to use the same upstream as in previous call,
|
||||||
|
//b/c different upstreams may have different blocks on the same height
|
||||||
|
api.read(JsonRpcRequest("eth_getBlockByNumber", listOf(it.toHex(), false)))
|
||||||
|
.subscribeOn(EthereumRpcHead.scheduler)
|
||||||
|
.timeout(Defaults.timeout, Mono.error(Exception("Block data not received")))
|
||||||
|
}
|
||||||
|
.map {
|
||||||
|
BlockContainer.fromEthereumJson(it.getResult())
|
||||||
|
}
|
||||||
|
.onErrorResume { err ->
|
||||||
|
log.debug("Failed to fetch latest block: ${err.message}")
|
||||||
|
Mono.empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -49,30 +49,7 @@ class EthereumRpcHead(
|
|||||||
val base = Flux.interval(interval)
|
val base = Flux.interval(interval)
|
||||||
.publishOn(scheduler)
|
.publishOn(scheduler)
|
||||||
.flatMap {
|
.flatMap {
|
||||||
api.read(JsonRpcRequest("eth_blockNumber", emptyList()))
|
getLatestBlock(api)
|
||||||
.subscribeOn(scheduler)
|
|
||||||
.timeout(Defaults.timeout, Mono.error(Exception("Block number not received")))
|
|
||||||
.flatMap {
|
|
||||||
if (it.error != null) {
|
|
||||||
Mono.error(it.error.asException(null))
|
|
||||||
} else {
|
|
||||||
val value = it.getResultAsProcessedString()
|
|
||||||
Mono.just(HexQuantity.from(value))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.flatMap {
|
|
||||||
//fetching by Block Height here, critical to use same upstream,
|
|
||||||
//different upstreams may have different blocks on the same height
|
|
||||||
api.read(JsonRpcRequest("eth_getBlockByNumber", listOf(it.toHex(), false)))
|
|
||||||
.subscribeOn(scheduler)
|
|
||||||
.timeout(Defaults.timeout, Mono.error(Exception("Block data not received")))
|
|
||||||
}
|
|
||||||
.map {
|
|
||||||
BlockContainer.fromEthereumJson(it.getResult())
|
|
||||||
}
|
|
||||||
.onErrorContinue { err, _ ->
|
|
||||||
log.debug("RPC error ${err.message}")
|
|
||||||
}
|
}
|
||||||
refreshSubscription = super.follow(base)
|
refreshSubscription = super.follow(base)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,9 +16,11 @@
|
|||||||
*/
|
*/
|
||||||
package io.emeraldpay.dshackle.upstream.ethereum
|
package io.emeraldpay.dshackle.upstream.ethereum
|
||||||
|
|
||||||
|
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcWsClient
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.context.Lifecycle
|
import org.springframework.context.Lifecycle
|
||||||
import reactor.core.Disposable
|
import reactor.core.Disposable
|
||||||
|
import reactor.core.publisher.Flux
|
||||||
|
|
||||||
class EthereumWsHead(
|
class EthereumWsHead(
|
||||||
private val ws: EthereumWsFactory.EthereumWs
|
private val ws: EthereumWsFactory.EthereumWs
|
||||||
@@ -34,7 +36,12 @@ class EthereumWsHead(
|
|||||||
|
|
||||||
override fun start() {
|
override fun start() {
|
||||||
this.subscription?.dispose()
|
this.subscription?.dispose()
|
||||||
this.subscription = super.follow(ws.getBlocksFlux())
|
val heads = Flux.merge(
|
||||||
|
// get the current block, not just wait for the next update
|
||||||
|
getLatestBlock(JsonRpcWsClient(ws)),
|
||||||
|
ws.getBlocksFlux()
|
||||||
|
)
|
||||||
|
this.subscription = super.follow(heads)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun stop() {
|
override fun stop() {
|
||||||
|
|||||||
Reference in New Issue
Block a user