problem: routes calls to upstreams that quorum wouldnt accept anyway (not-lagging quorum to lagging upstreams)

solution: select only possible acceptable upstreams before the call
This commit is contained in:
Igor Artamonov
2021-08-04 17:00:30 -04:00
parent 2f2a553cd4
commit 7cf86129f0
6 changed files with 98 additions and 2 deletions

View File

@@ -24,11 +24,16 @@ import io.emeraldpay.dshackle.Global
import io.emeraldpay.dshackle.quorum.QuorumReaderFactory
import io.emeraldpay.dshackle.quorum.QuorumRpcReader
import io.emeraldpay.dshackle.reader.Reader
import io.emeraldpay.dshackle.test.MultistreamHolderMock
import io.emeraldpay.dshackle.test.TestingCommons
import io.emeraldpay.dshackle.quorum.AlwaysQuorum
import io.emeraldpay.dshackle.upstream.Head
import io.emeraldpay.dshackle.upstream.Multistream
import io.emeraldpay.dshackle.upstream.Selector
import io.emeraldpay.dshackle.upstream.MultistreamHolder
import io.emeraldpay.dshackle.upstream.Upstream
import io.emeraldpay.dshackle.upstream.calls.DefaultEthereumMethods
import io.emeraldpay.dshackle.upstream.calls.ManagedCallMethods
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
import io.emeraldpay.grpc.Chain
@@ -290,6 +295,47 @@ class NativeCallSpec extends Specification {
}
}
def "Prepare call adds height selector for not-lagging quorum"() {
setup:
def methods = new ManagedCallMethods(
new DefaultEthereumMethods(Chain.ETHEREUM),
["foo_bar"] as Set, [] as Set
)
methods.setQuorum("foo_bar", "not_lagging")
def head = Mock(Head) {
1 * it.getCurrentHeight() >> 101
}
def multistream = new MultistreamHolderMock.EthereumMultistreamMock(Chain.ETHEREUM, TestingCommons.upstream())
multistream.customMethods = methods
multistream.customHead = head
def multistreamHolder = Mock(MultistreamHolder) {
_ * it.observeChains() >> Flux.empty()
}
def nativeCall = new NativeCall(multistreamHolder)
def req = BlockchainOuterClass.NativeCallRequest.newBuilder()
.setChain(Common.ChainRef.CHAIN_ETHEREUM)
.addItems(
BlockchainOuterClass.NativeCallItem.newBuilder()
.setId(1)
.setMethod("foo_bar")
)
.build()
when:
def act = nativeCall.prepareCall(req, multistream)
.collectList().block(Duration.ofSeconds(1)).first()
then:
act.matcher != null
act.matcher instanceof Selector.MultiMatcher
with((Selector.MultiMatcher) act.matcher) {
it.getMatchers().size() >= 1
it.getMatcher(Selector.HeightMatcher) != null
with(it.getMatcher(Selector.HeightMatcher)) {
it.height == 101
}
}
}
def "Parse empty params"() {
setup:
def nativeCall = new NativeCall(Stub(MultistreamHolder))

View File

@@ -19,9 +19,11 @@ package io.emeraldpay.dshackle.test
import io.emeraldpay.dshackle.BlockchainType
import io.emeraldpay.dshackle.cache.Caches
import io.emeraldpay.dshackle.upstream.Head
import io.emeraldpay.dshackle.upstream.Multistream
import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinMultistream
import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinRpcUpstream
import io.emeraldpay.dshackle.upstream.calls.CallMethods
import io.emeraldpay.dshackle.upstream.calls.DefaultEthereumMethods
import io.emeraldpay.dshackle.upstream.Upstream
import io.emeraldpay.dshackle.upstream.MultistreamHolder
@@ -100,11 +102,21 @@ class MultistreamHolderMock implements MultistreamHolder {
static class EthereumMultistreamMock extends EthereumMultistream {
EthereumReader customReader = null
CallMethods customMethods = null
Head customHead = null
EthereumMultistreamMock(@NotNull Chain chain, @NotNull List<EthereumUpstream> upstreams, @NotNull Caches caches) {
super(chain, upstreams, caches)
}
EthereumMultistreamMock(@NotNull Chain chain, @NotNull List<EthereumUpstream> upstreams) {
this(chain, upstreams, Caches.default())
}
EthereumMultistreamMock(@NotNull Chain chain, @NotNull EthereumUpstream upstream) {
this(chain, [upstream])
}
@Override
EthereumReader getReader() {
if (customReader != null) {
@@ -112,6 +124,22 @@ class MultistreamHolderMock implements MultistreamHolder {
}
return super.getReader()
}
@Override
CallMethods getMethods() {
if (customMethods != null) {
return customMethods
}
return super.getMethods()
}
@Override
Head getHead() {
if (customHead != null) {
return customHead
}
return super.getHead()
}
}
}

View File

@@ -26,6 +26,7 @@ import io.emeraldpay.dshackle.data.BlockId
import io.emeraldpay.dshackle.reader.EmptyReader
import io.emeraldpay.dshackle.reader.Reader
import io.emeraldpay.dshackle.upstream.Multistream
import io.emeraldpay.dshackle.upstream.calls.CallMethods
import io.emeraldpay.dshackle.upstream.calls.DirectCallMethods
import io.emeraldpay.dshackle.upstream.ethereum.EthereumMultistream
import io.emeraldpay.dshackle.upstream.ethereum.EthereumUpstream
@@ -49,6 +50,10 @@ class TestingCommons {
return new EthereumApiMock()
}
static EthereumUpstreamMock upstream() {
return new EthereumUpstreamMock(Chain.ETHEREUM, api())
}
static EthereumUpstreamMock upstream(String id, Reader<JsonRpcRequest, JsonRpcResponse> api) {
return new EthereumUpstreamMock(id, Chain.ETHEREUM, api)
}