refactoring fork choice rules out of abstract head and priority fork choice support for PoS Ethereum
This commit is contained in:
@@ -27,7 +27,7 @@ class HeightByHashAddingSpec extends Specification {
|
||||
|
||||
def block = new BlockContainer(
|
||||
12079192L, BlockId.from("0xa6af163aab691919c595e2a466f0a7b01f1dff8cfd9631dee811df57064c2d32"),
|
||||
BigInteger.ONE, Instant.now(), false, "".bytes, null, []
|
||||
BigInteger.ONE, Instant.now(), false, "".bytes, null, [], 0
|
||||
)
|
||||
|
||||
def "use memory if available"() {
|
||||
|
||||
@@ -86,7 +86,8 @@ class ReceiptMemCacheSpec extends Specification {
|
||||
false,
|
||||
"{}".bytes,
|
||||
null,
|
||||
[TxId.from(receipt.transactionHash)]
|
||||
[TxId.from(receipt.transactionHash)],
|
||||
0
|
||||
)
|
||||
|
||||
when:
|
||||
|
||||
@@ -271,7 +271,7 @@ class TrackBitcoinAddressSpec extends Specification {
|
||||
Head head = Mock(Head) {
|
||||
1 * getFlux() >> Flux.concat(
|
||||
Flux.just(
|
||||
new BlockContainer(0L, BlockId.from(hash1), BigInteger.ZERO, Instant.now(), false, null, null, [])
|
||||
new BlockContainer(0L, BlockId.from(hash1), BigInteger.ZERO, Instant.now(), false, null, null, [], 0)
|
||||
),
|
||||
blocks.asFlux()
|
||||
)
|
||||
@@ -312,7 +312,7 @@ class TrackBitcoinAddressSpec extends Specification {
|
||||
StepVerifier.create(resp)
|
||||
.expectNext("0")
|
||||
.then {
|
||||
blocks.tryEmitNext(new BlockContainer(1L, BlockId.from(hash1), BigInteger.ONE, Instant.now(), false, null, null, []))
|
||||
blocks.tryEmitNext(new BlockContainer(1L, BlockId.from(hash1), BigInteger.ONE, Instant.now(), false, null, null, [], 0))
|
||||
}
|
||||
.expectNext("1230000")
|
||||
.then {
|
||||
|
||||
@@ -142,7 +142,7 @@ class TrackBitcoinTxSpec extends Specification {
|
||||
def txid = "69cd44d7c641db82e69824523c7ac0c5c1e5628f025474529cf5ffe64527efc9"
|
||||
// start with the current block
|
||||
def next = Flux.fromIterable([10, 12, 13, 14, 15]).map { h ->
|
||||
new BlockContainer(h.longValue(), BlockId.from("0000000000000000000895d1b9d3898700e1deecc3b0e69f439aa77875e6042f"), BigInteger.ONE, Instant.now(), false, null, null, [])
|
||||
new BlockContainer(h.longValue(), BlockId.from("0000000000000000000895d1b9d3898700e1deecc3b0e69f439aa77875e6042f"), BigInteger.ONE, Instant.now(), false, null, null, [], 0)
|
||||
}
|
||||
Head head = Mock(Head) {
|
||||
1 * getFlux() >> next
|
||||
@@ -173,7 +173,7 @@ class TrackBitcoinTxSpec extends Specification {
|
||||
def txid = "69cd44d7c641db82e69824523c7ac0c5c1e5628f025474529cf5ffe64527efc9"
|
||||
// start with the current block
|
||||
def next = Flux.fromIterable([10, 12, 13]).map { h ->
|
||||
new BlockContainer(h.longValue(), BlockId.from("0000000000000000000895d1b9d3898700e1deecc3b0e69f439aa77875e6042f"), BigInteger.ONE, Instant.now(), false, null, null, [])
|
||||
new BlockContainer(h.longValue(), BlockId.from("0000000000000000000895d1b9d3898700e1deecc3b0e69f439aa77875e6042f"), BigInteger.ONE, Instant.now(), false, null, null, [], 0)
|
||||
}
|
||||
Head head = Mock(Head) {
|
||||
1 * getFlux() >> next
|
||||
@@ -268,7 +268,7 @@ class TrackBitcoinTxSpec extends Specification {
|
||||
])
|
||||
}
|
||||
def next = Flux.fromIterable([10, 11, 12]).map { h ->
|
||||
new BlockContainer(h.longValue(), BlockId.from("0000000000000000000895d1b9d3898700e1deecc3b0e69f439aa77875e6042f"), BigInteger.ONE, Instant.now(), false, null, null, [])
|
||||
new BlockContainer(h.longValue(), BlockId.from("0000000000000000000895d1b9d3898700e1deecc3b0e69f439aa77875e6042f"), BigInteger.ONE, Instant.now(), false, null, null, [], 0)
|
||||
}
|
||||
Head head = Mock(Head) {
|
||||
_ * getFlux() >> next
|
||||
|
||||
@@ -198,7 +198,7 @@ class TrackEthereumTxSpec extends Specification {
|
||||
def tx = new TrackEthereumTx.TxDetails(Chain.ETHEREUM, Instant.now(), TransactionId.from(txId), 6)
|
||||
def block = new BlockContainer(
|
||||
100, BlockId.from(txId), BigInteger.ONE, Instant.now(), false, "".bytes, null,
|
||||
[TxId.from(txId)]
|
||||
[TxId.from(txId)], 0
|
||||
)
|
||||
|
||||
when:
|
||||
@@ -220,7 +220,8 @@ class TrackEthereumTxSpec extends Specification {
|
||||
def tx = new TrackEthereumTx.TxDetails(Chain.ETHEREUM, Instant.now(), TransactionId.from(txId), 6)
|
||||
def block = new BlockContainer(
|
||||
100, BlockId.from(txId), BigInteger.ONE, Instant.now(), false, "".bytes, null,
|
||||
[TxId.from("0xa0e65cbc1b52a8ca60562112c6060552d882f16f34a9dba2ccdc05c0a6a27c22")]
|
||||
[TxId.from("0xa0e65cbc1b52a8ca60562112c6060552d882f16f34a9dba2ccdc05c0a6a27c22")],
|
||||
0
|
||||
)
|
||||
apiMock.answer("eth_getTransactionByHash", [txId], null)
|
||||
|
||||
|
||||
@@ -111,7 +111,8 @@ class TestingCommons {
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
[]
|
||||
[],
|
||||
0
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,9 @@ package io.emeraldpay.dshackle.upstream
|
||||
|
||||
import io.emeraldpay.dshackle.data.BlockContainer
|
||||
import io.emeraldpay.dshackle.data.BlockId
|
||||
import io.emeraldpay.dshackle.upstream.forkchoice.ForkChoice
|
||||
import io.emeraldpay.dshackle.upstream.forkchoice.MostWorkForkChoice
|
||||
import org.jetbrains.annotations.NotNull
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Sinks
|
||||
import reactor.test.StepVerifier
|
||||
@@ -31,7 +34,7 @@ class AbstractHeadSpec extends Specification {
|
||||
def blocks = [1L, 2, 3, 4].collect { i ->
|
||||
byte[] hash = new byte[32]
|
||||
hash[0] = i as byte
|
||||
new BlockContainer(i, BlockId.from(hash), BigInteger.valueOf(i), Instant.now(), false, null, null, [])
|
||||
new BlockContainer(i, BlockId.from(hash), BigInteger.valueOf(i), Instant.now(), false, null, null, [], 0)
|
||||
}
|
||||
|
||||
def "Calls beforeBlock on each block"() {
|
||||
@@ -85,7 +88,7 @@ class AbstractHeadSpec extends Specification {
|
||||
.verify(Duration.ofSeconds(1))
|
||||
}
|
||||
|
||||
def "Ignores block will less difficulty"() {
|
||||
def "Ignores block that is filtered by forkchoice"() {
|
||||
setup:
|
||||
Sinks.Many<BlockContainer> source = Sinks.many().unicast().onBackpressureBuffer()
|
||||
def head = new TestHead()
|
||||
@@ -93,7 +96,7 @@ class AbstractHeadSpec extends Specification {
|
||||
blocks[1].height, BlockId.from(blocks[1].hash.value.clone().tap { it[1] = 0xff as byte }),
|
||||
blocks[1].difficulty - 1,
|
||||
Instant.now(),
|
||||
false, null, null, []
|
||||
false, null, null, [], 0
|
||||
)
|
||||
when:
|
||||
head.follow(source.asFlux())
|
||||
@@ -113,6 +116,23 @@ class AbstractHeadSpec extends Specification {
|
||||
}
|
||||
|
||||
class TestHead extends AbstractHead {
|
||||
TestHead() {
|
||||
super(new ForkChoice() {
|
||||
@Override
|
||||
boolean filter(@NotNull BlockContainer block) {
|
||||
return block.hash != BlockId.from("02ff000000000000000000000000000000000000000000000000000000000000")
|
||||
}
|
||||
|
||||
@Override
|
||||
ForkChoice.ChoiceResult choose(@NotNull BlockContainer block) {
|
||||
return new ForkChoice.ChoiceResult.Updated(block)
|
||||
}
|
||||
|
||||
@Override
|
||||
BlockContainer getHead() {
|
||||
return null
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
package io.emeraldpay.dshackle.upstream
|
||||
|
||||
import io.emeraldpay.dshackle.data.BlockContainer
|
||||
import io.emeraldpay.etherjar.domain.BlockHash
|
||||
import io.emeraldpay.etherjar.rpc.json.BlockJson
|
||||
import spock.lang.Specification
|
||||
|
||||
import java.time.Instant
|
||||
|
||||
class DistanceExtractorSpec extends Specification {
|
||||
def "Correct distance for PoW"() {
|
||||
expect:
|
||||
def top = new BlockJson().with {
|
||||
it.number = topHeight
|
||||
it.totalDifficulty = topDiff
|
||||
it.hash = BlockHash.from("0x3ec2ebf5d0ec474d0ac6bc50d2770d8409ad76e119968e7919f85d5ec8915123")
|
||||
it.timestamp = Instant.now()
|
||||
return it
|
||||
}
|
||||
def curr = new BlockJson().with {
|
||||
it.number = currHeight
|
||||
it.totalDifficulty = currDiff
|
||||
it.hash = BlockHash.from("0x3ec2ebf5d0ec474d0ac6bc50d2770d8409ad76e119968e7919f85d5ec8915123")
|
||||
it.timestamp = Instant.now()
|
||||
return it
|
||||
}
|
||||
delta as DistanceExtractor.ChainDistance == DistanceExtractor.@Companion.extractPowDistance(BlockContainer.from(top), BlockContainer.from(curr))
|
||||
where:
|
||||
topHeight | topDiff | currHeight | currDiff | delta
|
||||
100 | 1000 | 100 | 1000 | new DistanceExtractor.ChainDistance.Distance(0)
|
||||
101 | 1010 | 100 | 1000 | new DistanceExtractor.ChainDistance.Distance(1)
|
||||
102 | 1020 | 100 | 1000 | new DistanceExtractor.ChainDistance.Distance(2)
|
||||
103 | 1030 | 100 | 1000 | new DistanceExtractor.ChainDistance.Distance(3)
|
||||
150 | 1500 | 100 | 1000 | new DistanceExtractor.ChainDistance.Distance(50)
|
||||
|
||||
100 | 1000 | 101 | 1010 | new DistanceExtractor.ChainDistance.Distance(0)
|
||||
100 | 1000 | 102 | 1020 | new DistanceExtractor.ChainDistance.Distance(0)
|
||||
100 | 1000 | 100 | 1010 | DistanceExtractor.ChainDistance.Fork.INSTANCE
|
||||
100 | 1100 | 100 | 1000 | DistanceExtractor.ChainDistance.Fork.INSTANCE
|
||||
}
|
||||
|
||||
def "Correct distance for priority"() {
|
||||
setup:
|
||||
def hash1 = "0x3ec2ebf5d0ec474d0ac6bc50d2770d8409ad76e119968e7919f85d5ec8915123"
|
||||
def hash2 = "0x3ec2ebf5d0ec474d0ac6bc50d2770d8409ad76e119968e7919f85d5ec8915124"
|
||||
expect:
|
||||
def top = new BlockJson().with {
|
||||
it.number = topHeight
|
||||
it.totalDifficulty = 0
|
||||
it.hash = BlockHash.from(hashA == 0 ? hash1 : hash2)
|
||||
it.timestamp = Instant.now()
|
||||
return it
|
||||
}
|
||||
def curr = new BlockJson().with {
|
||||
it.number = currHeight
|
||||
it.totalDifficulty = 0
|
||||
it.hash = BlockHash.from(hashB == 0 ? hash1 : hash2)
|
||||
it.timestamp = Instant.now()
|
||||
return it
|
||||
}
|
||||
delta as DistanceExtractor.ChainDistance == DistanceExtractor.@Companion.extractPriorityDistance(BlockContainer.from(top), BlockContainer.from(curr))
|
||||
where:
|
||||
topHeight | hashA | currHeight | hashB || delta
|
||||
100 | 0 | 100 | 0 || new DistanceExtractor.ChainDistance.Distance(0)
|
||||
101 | 0 | 100 | 1 || new DistanceExtractor.ChainDistance.Distance(1)
|
||||
102 | 0 | 100 | 1 || new DistanceExtractor.ChainDistance.Distance(2)
|
||||
103 | 0 | 100 | 1 || new DistanceExtractor.ChainDistance.Distance(3)
|
||||
150 | 0 | 100 | 1 || new DistanceExtractor.ChainDistance.Distance(50)
|
||||
|
||||
100 | 0 | 101 | 1 || DistanceExtractor.ChainDistance.Fork.INSTANCE
|
||||
100 | 0 | 102 | 1 || DistanceExtractor.ChainDistance.Fork.INSTANCE
|
||||
100 | 0 | 100 | 1 || DistanceExtractor.ChainDistance.Fork.INSTANCE
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import io.emeraldpay.dshackle.test.TestingCommons
|
||||
import io.emeraldpay.dshackle.upstream.calls.DefaultEthereumMethods
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumUpstream
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.connectors.EthereumConnectorFactory
|
||||
import io.emeraldpay.dshackle.upstream.forkchoice.MostWorkForkChoice
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import reactor.test.StepVerifier
|
||||
import spock.lang.Retry
|
||||
@@ -47,7 +48,7 @@ class FilteredApisSpec extends Specification {
|
||||
def httpFactory = Mock(HttpFactory) {
|
||||
create(_, _) >> TestingCommons.api().tap { it.id = "${i++}" }
|
||||
}
|
||||
def connectorFactory = new EthereumConnectorFactory(false, null, httpFactory)
|
||||
def connectorFactory = new EthereumConnectorFactory(false, null, httpFactory, new MostWorkForkChoice())
|
||||
new EthereumUpstream(
|
||||
"test",
|
||||
Chain.ETHEREUM,
|
||||
|
||||
@@ -111,45 +111,10 @@ class HeadLagObserverSpec extends Specification {
|
||||
.verifyComplete()
|
||||
}
|
||||
|
||||
def "Correct distance"() {
|
||||
setup:
|
||||
Head master = Mock()
|
||||
HeadLagObserver observer = new TestHeadLagObserver(master, [])
|
||||
expect:
|
||||
def top = new BlockJson().with {
|
||||
it.number = topHeight
|
||||
it.totalDifficulty = topDiff
|
||||
it.hash = BlockHash.from("0x3ec2ebf5d0ec474d0ac6bc50d2770d8409ad76e119968e7919f85d5ec8915123")
|
||||
it.timestamp = Instant.now()
|
||||
return it
|
||||
}
|
||||
def curr = new BlockJson().with {
|
||||
it.number = currHeight
|
||||
it.totalDifficulty = currDiff
|
||||
it.hash = BlockHash.from("0x3ec2ebf5d0ec474d0ac6bc50d2770d8409ad76e119968e7919f85d5ec8915123")
|
||||
it.timestamp = Instant.now()
|
||||
return it
|
||||
}
|
||||
delta as Long == observer.extractDistance(BlockContainer.from(top), BlockContainer.from(curr))
|
||||
where:
|
||||
topHeight | topDiff | currHeight | currDiff | delta
|
||||
100 | 1000 | 100 | 1000 | 0
|
||||
101 | 1010 | 100 | 1000 | 1
|
||||
102 | 1020 | 100 | 1000 | 2
|
||||
103 | 1030 | 100 | 1000 | 3
|
||||
150 | 1500 | 100 | 1000 | 50
|
||||
|
||||
100 | 1000 | 101 | 1010 | 0
|
||||
100 | 1000 | 102 | 1020 | 0
|
||||
100 | 1000 | 100 | 1010 | 11
|
||||
100 | 1100 | 100 | 1000 | 11
|
||||
|
||||
}
|
||||
|
||||
class TestHeadLagObserver extends HeadLagObserver {
|
||||
|
||||
TestHeadLagObserver(@NotNull Head master, @NotNull Collection<? extends Upstream> followers) {
|
||||
super(master, followers)
|
||||
super(master, followers, DistanceExtractor.@Companion::extractPowDistance)
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package io.emeraldpay.dshackle.upstream
|
||||
|
||||
import io.emeraldpay.dshackle.upstream.forkchoice.MostWorkForkChoice
|
||||
import org.springframework.context.Lifecycle
|
||||
import reactor.core.publisher.Flux
|
||||
import spock.lang.Specification
|
||||
@@ -36,7 +37,7 @@ class MergedHeadSpec extends Specification {
|
||||
}
|
||||
|
||||
when:
|
||||
def merged = new MergedHead([head1, head2, head3])
|
||||
def merged = new MergedHead([head1, head2, head3], new MostWorkForkChoice())
|
||||
merged.start()
|
||||
|
||||
then:
|
||||
@@ -44,11 +45,17 @@ class MergedHeadSpec extends Specification {
|
||||
}
|
||||
|
||||
class TestHead1 extends AbstractHead {
|
||||
|
||||
TestHead1() {
|
||||
super(new MostWorkForkChoice())
|
||||
}
|
||||
}
|
||||
|
||||
class TestHead2 extends AbstractHead implements Lifecycle {
|
||||
|
||||
TestHead2() {
|
||||
super(new MostWorkForkChoice())
|
||||
}
|
||||
|
||||
@Override
|
||||
void start() {
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import io.emeraldpay.dshackle.Global
|
||||
import io.emeraldpay.dshackle.data.BlockContainer
|
||||
import io.emeraldpay.dshackle.test.TestingCommons
|
||||
import io.emeraldpay.dshackle.upstream.forkchoice.MostWorkForkChoice
|
||||
import io.emeraldpay.etherjar.domain.BlockHash
|
||||
import io.emeraldpay.etherjar.rpc.json.BlockJson
|
||||
import reactor.core.publisher.Flux
|
||||
@@ -30,7 +31,7 @@ import java.time.Instant
|
||||
|
||||
class DefaultEthereumHeadSpec extends Specification {
|
||||
|
||||
DefaultEthereumHead head = new DefaultEthereumHead()
|
||||
DefaultEthereumHead head = new DefaultEthereumHead(new MostWorkForkChoice())
|
||||
ObjectMapper objectMapper = Global.objectMapper
|
||||
|
||||
def blocks = (10L..20L).collect { i ->
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package io.emeraldpay.dshackle.upstream.forkchoice
|
||||
|
||||
import io.emeraldpay.dshackle.data.BlockContainer
|
||||
import io.emeraldpay.dshackle.data.BlockId
|
||||
import spock.lang.Specification
|
||||
|
||||
import java.time.Instant
|
||||
|
||||
class MostWorkForkChoiceSpec extends Specification {
|
||||
|
||||
def blocks = [1L, 2, 3, 4].collect { i ->
|
||||
byte[] hash = new byte[32]
|
||||
hash[0] = i as byte
|
||||
new BlockContainer(i, BlockId.from(hash), BigInteger.valueOf(i), Instant.now(), false, null, null, [], 0)
|
||||
}
|
||||
|
||||
def "filters blocks"() {
|
||||
def choice = new MostWorkForkChoice()
|
||||
choice.choose(blocks[1])
|
||||
expect:
|
||||
!choice.filter(blocks[0])
|
||||
choice.filter(blocks[2])
|
||||
}
|
||||
|
||||
def "chooses correct block as head"() {
|
||||
def choice = new MostWorkForkChoice()
|
||||
choice.choose(blocks[1])
|
||||
when:
|
||||
choice.choose(blocks[0])
|
||||
then:
|
||||
choice.getHead() == blocks[1]
|
||||
when:
|
||||
choice.choose(blocks[2])
|
||||
then:
|
||||
choice.getHead() == blocks[2]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package io.emeraldpay.dshackle.upstream.forkchoice
|
||||
|
||||
import io.emeraldpay.dshackle.data.BlockContainer
|
||||
import io.emeraldpay.dshackle.data.BlockId
|
||||
import spock.lang.Specification
|
||||
|
||||
import java.time.Instant
|
||||
|
||||
class NoChoiceWithPriorityForkChoiceSpec extends Specification {
|
||||
def blocks = [1L, 2, 3, 4].collect { i ->
|
||||
byte[] hash = new byte[32]
|
||||
hash[0] = i as byte
|
||||
new BlockContainer(i, BlockId.from(hash), BigInteger.valueOf(i), Instant.now(), false, null, null, [], 0)
|
||||
}
|
||||
|
||||
def "filters blocks"() {
|
||||
def blockR0 = blocks[0].copyWithRating(10)
|
||||
def blockR1 = blocks[1].copyWithRating(10)
|
||||
def choice = new NoChoiceWithPriorityForkChoice(10)
|
||||
when:
|
||||
choice.choose(blocks[0])
|
||||
then:
|
||||
choice.getHead() == blockR0
|
||||
when:
|
||||
choice.choose(blocks[1])
|
||||
then:
|
||||
choice.getHead() == blockR1
|
||||
when:
|
||||
choice.choose(blocks[0])
|
||||
then:
|
||||
choice.getHead() == blocks[1]
|
||||
}
|
||||
|
||||
def "chooses blocks and adds rating"() {
|
||||
def blockR0 = blocks[0].copyWithRating(10)
|
||||
def blockR1 = blocks[1].copyWithRating(10)
|
||||
def choice = new NoChoiceWithPriorityForkChoice(10)
|
||||
when:
|
||||
choice.choose(blocks[0])
|
||||
then:
|
||||
choice.getHead() == blockR0
|
||||
when:
|
||||
choice.choose(blocks[1])
|
||||
then:
|
||||
choice.getHead() == blockR1
|
||||
when:
|
||||
choice.choose(blocks[0])
|
||||
then:
|
||||
choice.getHead() == blockR1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package io.emeraldpay.dshackle.upstream.forkchoice
|
||||
|
||||
import io.emeraldpay.dshackle.data.BlockContainer
|
||||
import io.emeraldpay.dshackle.data.BlockId
|
||||
import spock.lang.Specification
|
||||
|
||||
import java.time.Instant
|
||||
|
||||
class PriorityForkChoiceSpec extends Specification {
|
||||
def blocks = [1L, 2, 3, 4].collect { i ->
|
||||
byte[] hash = new byte[32]
|
||||
hash[0] = i as byte
|
||||
new BlockContainer(i, BlockId.from(hash), BigInteger.valueOf(i), Instant.now(), false, null, null, [], i.toInteger())
|
||||
}
|
||||
def "filters blocks"() {
|
||||
def choice = new PriorityForkChoice()
|
||||
choice.choose(blocks[1])
|
||||
expect:
|
||||
!choice.filter(blocks[0])
|
||||
choice.filter(blocks[2])
|
||||
!choice.filter(blocks[1])
|
||||
}
|
||||
|
||||
def "chooses correct block according to node rating"() {
|
||||
def choice = new PriorityForkChoice()
|
||||
choice.choose(blocks[1])
|
||||
when:
|
||||
choice.choose(blocks[0])
|
||||
then:
|
||||
choice.getHead() == blocks[1]
|
||||
when:
|
||||
choice.choose(blocks[2])
|
||||
then:
|
||||
choice.getHead() == blocks[2]
|
||||
when:
|
||||
def seenblock = blocks[1].copyWithRating(20)
|
||||
choice.choose(seenblock)
|
||||
then:
|
||||
choice.getHead() == blocks[2]
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import io.emeraldpay.api.proto.Common
|
||||
import io.emeraldpay.dshackle.test.MockGrpcServer
|
||||
import io.emeraldpay.dshackle.test.TestingCommons
|
||||
import io.emeraldpay.dshackle.upstream.DefaultUpstream
|
||||
import io.emeraldpay.dshackle.upstream.forkchoice.MostWorkForkChoice
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import io.grpc.stub.StreamObserver
|
||||
import reactor.test.StepVerifier
|
||||
@@ -60,7 +61,7 @@ class GrpcHeadSpec extends Specification {
|
||||
Chain.BITCOIN,
|
||||
Stub(DefaultUpstream),
|
||||
client,
|
||||
convert, null
|
||||
convert, null, new MostWorkForkChoice()
|
||||
)
|
||||
when:
|
||||
def act = head.getFlux()
|
||||
@@ -121,7 +122,7 @@ class GrpcHeadSpec extends Specification {
|
||||
Chain.BITCOIN,
|
||||
Stub(DefaultUpstream),
|
||||
client,
|
||||
convert, null
|
||||
convert, null, new MostWorkForkChoice()
|
||||
)
|
||||
when:
|
||||
def act = head.getFlux()
|
||||
|
||||
Reference in New Issue
Block a user