problem: lag is not observed on bitcoin
This commit is contained in:
@@ -21,8 +21,10 @@ 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
|
import reactor.core.publisher.Flux
|
||||||
|
import reactor.core.scheduler.Schedulers
|
||||||
import reactor.util.function.Tuple2
|
import reactor.util.function.Tuple2
|
||||||
import reactor.util.function.Tuples
|
import reactor.util.function.Tuples
|
||||||
|
import java.time.Duration
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Observer group of upstreams and defined a distance in blocks (lag) between a leader (best height/difficulty) and
|
* Observer group of upstreams and defined a distance in blocks (lag) between a leader (best height/difficulty) and
|
||||||
@@ -38,6 +40,7 @@ abstract class HeadLagObserver(
|
|||||||
private var current: Disposable? = null
|
private var current: Disposable? = null
|
||||||
|
|
||||||
override fun start() {
|
override fun start() {
|
||||||
|
current?.dispose()
|
||||||
current = subscription().subscribe { }
|
current = subscription().subscribe { }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,12 +64,15 @@ abstract class HeadLagObserver(
|
|||||||
fun probeFollowers(top: BlockContainer): Flux<Tuple2<Long, Upstream>> {
|
fun probeFollowers(top: BlockContainer): Flux<Tuple2<Long, Upstream>> {
|
||||||
return Flux.fromIterable(followers)
|
return Flux.fromIterable(followers)
|
||||||
.parallel(followers.size)
|
.parallel(followers.size)
|
||||||
.flatMap { mapLagging(top, it, getCurrentBlocks(it)) }
|
.flatMap { up -> mapLagging(top, up, getCurrentBlocks(up)).subscribeOn(Schedulers.elastic()) }
|
||||||
.sequential()
|
.sequential()
|
||||||
.onErrorContinue { t, _ -> log.warn("Failed to update lagging distance", t) }
|
.onErrorContinue { t, _ -> log.warn("Failed to update lagging distance", t) }
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract fun getCurrentBlocks(up: Upstream): Flux<BlockContainer>
|
open fun getCurrentBlocks(up: Upstream): Flux<BlockContainer> {
|
||||||
|
val head = up.getHead()
|
||||||
|
return head.getFlux().take(Duration.ofSeconds(1))
|
||||||
|
}
|
||||||
|
|
||||||
fun mapLagging(top: BlockContainer, up: Upstream, blocks: Flux<BlockContainer>): Flux<Tuple2<Long, Upstream>> {
|
fun mapLagging(top: BlockContainer, up: Upstream, blocks: Flux<BlockContainer>): Flux<Tuple2<Long, Upstream>> {
|
||||||
return blocks
|
return blocks
|
||||||
@@ -78,11 +84,14 @@ abstract class HeadLagObserver(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract fun extractDistance(top: BlockContainer, curr: BlockContainer): Long
|
open fun extractDistance(top: BlockContainer, curr: BlockContainer): Long {
|
||||||
|
return when {
|
||||||
fun forkDistance(top: BlockContainer, curr: BlockContainer): Long {
|
curr.height > top.height -> if (curr.difficulty >= top.difficulty) 0 else forkDistance(top, curr)
|
||||||
//TODO look for common ancestor? though it may be a corruption
|
curr.height == top.height -> if (curr.difficulty == top.difficulty) 0 else forkDistance(top, curr)
|
||||||
return 6
|
else -> top.height - curr.height
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract fun forkDistance(top: BlockContainer, curr: BlockContainer): Long
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2020 EmeraldPay, Inc
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package io.emeraldpay.dshackle.upstream.bitcoin
|
||||||
|
|
||||||
|
import io.emeraldpay.dshackle.data.BlockContainer
|
||||||
|
import io.emeraldpay.dshackle.upstream.Head
|
||||||
|
import io.emeraldpay.dshackle.upstream.HeadLagObserver
|
||||||
|
import io.emeraldpay.dshackle.upstream.Upstream
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
|
||||||
|
class BitcoinHeadLagObserver(
|
||||||
|
master: Head,
|
||||||
|
followers: Collection<Upstream>
|
||||||
|
) : HeadLagObserver(master, followers) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val log = LoggerFactory.getLogger(BitcoinHeadLagObserver::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun forkDistance(top: BlockContainer, curr: BlockContainer): Long {
|
||||||
|
//TODO fetch actual blocks
|
||||||
|
return 3
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -64,8 +64,8 @@ open class BitcoinMultistream(
|
|||||||
val newHead = MergedHead(upstreams.map { it.getHead() }).apply {
|
val newHead = MergedHead(upstreams.map { it.getHead() }).apply {
|
||||||
this.start()
|
this.start()
|
||||||
}
|
}
|
||||||
// val lagObserver = TODO
|
val lagObserver = BitcoinHeadLagObserver(newHead, upstreams)
|
||||||
// this.lagObserver = lagObserver
|
this.lagObserver = lagObserver
|
||||||
newHead
|
newHead
|
||||||
}
|
}
|
||||||
onHeadUpdated(head)
|
onHeadUpdated(head)
|
||||||
|
|||||||
@@ -33,16 +33,9 @@ class EthereumHeadLagObserver(
|
|||||||
private val log = LoggerFactory.getLogger(EthereumHeadLagObserver::class.java)
|
private val log = LoggerFactory.getLogger(EthereumHeadLagObserver::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getCurrentBlocks(up: Upstream): Flux<BlockContainer> {
|
override fun forkDistance(top: BlockContainer, curr: BlockContainer): Long {
|
||||||
val head = up.getHead()
|
//TODO look for common ancestor? though it may be a corruption
|
||||||
return head.getFlux().take(Duration.ofSeconds(1))
|
return 6
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun extractDistance(top: BlockContainer, curr: BlockContainer): Long {
|
|
||||||
return when {
|
|
||||||
curr.height > top.height -> if (curr.difficulty >= top.difficulty) 0 else forkDistance(top, curr)
|
|
||||||
curr.height == top.height -> if (curr.difficulty == top.difficulty) 0 else forkDistance(top, curr)
|
|
||||||
else -> top.height - curr.height
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package io.emeraldpay.dshackle.upstream.ethereum
|
package io.emeraldpay.dshackle.upstream
|
||||||
|
|
||||||
import io.emeraldpay.dshackle.data.BlockContainer
|
import io.emeraldpay.dshackle.data.BlockContainer
|
||||||
import io.emeraldpay.dshackle.upstream.Head
|
import io.emeraldpay.dshackle.upstream.Head
|
||||||
@@ -22,6 +22,7 @@ import io.emeraldpay.dshackle.upstream.HeadLagObserver
|
|||||||
import io.emeraldpay.dshackle.upstream.Upstream
|
import io.emeraldpay.dshackle.upstream.Upstream
|
||||||
import io.infinitape.etherjar.domain.BlockHash
|
import io.infinitape.etherjar.domain.BlockHash
|
||||||
import io.infinitape.etherjar.rpc.json.BlockJson
|
import io.infinitape.etherjar.rpc.json.BlockJson
|
||||||
|
import org.jetbrains.annotations.NotNull
|
||||||
import reactor.core.publisher.Flux
|
import reactor.core.publisher.Flux
|
||||||
import reactor.core.publisher.TopicProcessor
|
import reactor.core.publisher.TopicProcessor
|
||||||
import reactor.test.StepVerifier
|
import reactor.test.StepVerifier
|
||||||
@@ -31,7 +32,7 @@ import spock.lang.Specification
|
|||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
|
||||||
class EthereumHeadLagObserverSpec extends Specification {
|
class HeadLagObserverSpec extends Specification {
|
||||||
|
|
||||||
def "Updates lag distance"() {
|
def "Updates lag distance"() {
|
||||||
setup:
|
setup:
|
||||||
@@ -72,7 +73,7 @@ class EthereumHeadLagObserverSpec extends Specification {
|
|||||||
1 * up2.setLag(1)
|
1 * up2.setLag(1)
|
||||||
1 * up2.setLag(0)
|
1 * up2.setLag(0)
|
||||||
|
|
||||||
HeadLagObserver observer = new EthereumHeadLagObserver(master, [up1, up2])
|
HeadLagObserver observer = new TestHeadLagObserver(master, [up1, up2])
|
||||||
when:
|
when:
|
||||||
def act = observer.subscription().take(Duration.ofMillis(1200))
|
def act = observer.subscription().take(Duration.ofMillis(1200))
|
||||||
|
|
||||||
@@ -86,7 +87,7 @@ class EthereumHeadLagObserverSpec extends Specification {
|
|||||||
def "Probes until there is no difference"() {
|
def "Probes until there is no difference"() {
|
||||||
setup:
|
setup:
|
||||||
Head master = Mock()
|
Head master = Mock()
|
||||||
HeadLagObserver observer = new EthereumHeadLagObserver(master, [])
|
HeadLagObserver observer = new TestHeadLagObserver(master, [])
|
||||||
Upstream up = Mock()
|
Upstream up = Mock()
|
||||||
|
|
||||||
def blocks = [100, 101, 102].collect { i ->
|
def blocks = [100, 101, 102].collect { i ->
|
||||||
@@ -113,7 +114,7 @@ class EthereumHeadLagObserverSpec extends Specification {
|
|||||||
def "Correct distance"() {
|
def "Correct distance"() {
|
||||||
setup:
|
setup:
|
||||||
Head master = Mock()
|
Head master = Mock()
|
||||||
HeadLagObserver observer = new EthereumHeadLagObserver(master, [])
|
HeadLagObserver observer = new TestHeadLagObserver(master, [])
|
||||||
expect:
|
expect:
|
||||||
def top = new BlockJson().with {
|
def top = new BlockJson().with {
|
||||||
it.number = topHeight
|
it.number = topHeight
|
||||||
@@ -140,8 +141,20 @@ class EthereumHeadLagObserverSpec extends Specification {
|
|||||||
|
|
||||||
100 | 1000 | 101 | 1010 | 0
|
100 | 1000 | 101 | 1010 | 0
|
||||||
100 | 1000 | 102 | 1020 | 0
|
100 | 1000 | 102 | 1020 | 0
|
||||||
100 | 1000 | 100 | 1010 | 6
|
100 | 1000 | 100 | 1010 | 11
|
||||||
100 | 1100 | 100 | 1000 | 6
|
100 | 1100 | 100 | 1000 | 11
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class TestHeadLagObserver extends HeadLagObserver {
|
||||||
|
|
||||||
|
TestHeadLagObserver(@NotNull Head master, @NotNull Collection<? extends Upstream> followers) {
|
||||||
|
super(master, followers)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
long forkDistance(@NotNull BlockContainer top, @NotNull BlockContainer curr) {
|
||||||
|
return 11
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user