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

@@ -23,6 +23,11 @@ import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcException
import io.infinitape.etherjar.rpc.RpcException
import java.util.concurrent.atomic.AtomicReference
/**
* Accepts a response only from a "synced" upstreams, where "maxLag" specifies how many blocks it may be behind to be considered as "synced"
*
* NOTE: NativeCall checks the quorums and applies a HeightSelector if NotLaggingQuorum is enabled for a call
*/
class NotLaggingQuorum(val maxLag: Long = 0): CallQuorum {
private val result: AtomicReference<ByteArray> = AtomicReference()

View File

@@ -24,6 +24,7 @@ import io.emeraldpay.dshackle.SilentException
import io.emeraldpay.dshackle.upstream.*
import io.emeraldpay.dshackle.quorum.AlwaysQuorum
import io.emeraldpay.dshackle.quorum.CallQuorum
import io.emeraldpay.dshackle.quorum.NotLaggingQuorum
import io.emeraldpay.dshackle.quorum.QuorumReaderFactory
import io.emeraldpay.dshackle.upstream.calls.EthereumCallSelector
import io.emeraldpay.dshackle.upstream.ethereum.EthereumMultistream
@@ -151,12 +152,19 @@ open class NativeCall(
.withMatcher(csm)
.forMethod(method)
.forLabels(Selector.convertToMatcher(request.selector))
.build()
val callQuorum = upstream.getMethods().getQuorumFor(method) ?: AlwaysQuorum()
callQuorum.init(upstream.getHead())
CallContext(it.id, upstream, matcher, callQuorum, RawCallDetails(method, params))
// for NotLaggingQuorum it makes sense to select compatible upstreams before the call
if (callQuorum is NotLaggingQuorum) {
val lag = callQuorum.maxLag
val minHeight = ((upstream.getHead().getCurrentHeight() ?: 0) - lag).coerceAtLeast(0)
val heightMatcher = Selector.HeightMatcher(minHeight)
matcher.withMatcher(heightMatcher)
}
CallContext(it.id, upstream, matcher.build(), callQuorum, RawCallDetails(method, params))
}
}
}

View File

@@ -115,6 +115,10 @@ class Selector {
return matchers.all { it.matches(up) }
}
fun getMatchers(): Collection<Matcher> {
return Collections.unmodifiableCollection(matchers)
}
fun <T : Matcher> getMatcher(type: Class<T>): T? {
return matchers.find { type.isAssignableFrom(it.javaClass) } as T?
}