solution: refactoring
This commit is contained in:
@@ -17,6 +17,7 @@ package io.emeraldpay.dshackle.rpc
|
||||
|
||||
import io.emeraldpay.api.proto.BlockchainOuterClass
|
||||
import io.emeraldpay.api.proto.Common
|
||||
import io.emeraldpay.dshackle.startup.QuorumForLabels
|
||||
import io.emeraldpay.dshackle.upstream.*
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumUpstream
|
||||
import io.emeraldpay.dshackle.upstream.grpc.GrpcUpstream
|
||||
@@ -43,13 +44,13 @@ class Describe(
|
||||
.setStatus(status)
|
||||
chainUpstreams.getAll().let { ups ->
|
||||
ups.forEach { up ->
|
||||
val nodes = NodeDetailsList()
|
||||
val nodes = QuorumForLabels()
|
||||
if (up is EthereumUpstream) {
|
||||
nodes.add(up.node)
|
||||
} else if (up is GrpcUpstream) {
|
||||
nodes.add(up.getNodes())
|
||||
}
|
||||
nodes.getNodes().forEach { node ->
|
||||
nodes.getAll().forEach { node ->
|
||||
val nodeDetails = BlockchainOuterClass.NodeDetails.newBuilder()
|
||||
.setQuorum(node.quorum)
|
||||
.addAllLabels(node.labels.entries.map { label ->
|
||||
|
||||
@@ -13,12 +13,14 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.emeraldpay.dshackle.upstream
|
||||
package io.emeraldpay.dshackle.startup
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import io.emeraldpay.dshackle.FileResolver
|
||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||
import io.emeraldpay.dshackle.config.UpstreamsConfigReader
|
||||
import io.emeraldpay.dshackle.upstream.CurrentUpstreams
|
||||
import io.emeraldpay.dshackle.upstream.calls.ManagedCallMethods
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.DirectEthereumApi
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumUpstream
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumWs
|
||||
@@ -172,7 +174,7 @@ open class ConfiguredUpstreams(
|
||||
val ethereumUpstream = EthereumUpstream(
|
||||
config.id!!,
|
||||
chain, rpcApi!!, wsApi, options,
|
||||
NodeDetailsList.NodeDetails(1, config.labels),
|
||||
QuorumForLabels.QuorumItem(1, config.labels),
|
||||
methods)
|
||||
ethereumUpstream.start()
|
||||
currentUpstreams.update(UpstreamChange(chain, ethereumUpstream, UpstreamChange.ChangeType.ADDED))
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.emeraldpay.dshackle.upstream
|
||||
package io.emeraldpay.dshackle.startup
|
||||
|
||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||
import java.util.*
|
||||
@@ -22,17 +22,20 @@ import kotlin.collections.ArrayList
|
||||
import kotlin.concurrent.read
|
||||
import kotlin.concurrent.write
|
||||
|
||||
class NodeDetailsList {
|
||||
/**
|
||||
* Summary details over few upstream nodes. Provides aggregate quorum for nodes with particular label
|
||||
*/
|
||||
class QuorumForLabels {
|
||||
|
||||
private val lock = ReentrantReadWriteLock()
|
||||
private val nodes = ArrayList<NodeDetails>()
|
||||
private val nodes = ArrayList<QuorumItem>()
|
||||
|
||||
fun add(node: NodeDetails) {
|
||||
fun add(node: QuorumItem) {
|
||||
lock.read {
|
||||
val existing = nodes.find { it.labels == node.labels }
|
||||
lock.write {
|
||||
if (existing != null) {
|
||||
val merged = NodeDetails(existing.quorum + node.quorum, existing.labels)
|
||||
val merged = QuorumItem(existing.quorum + node.quorum, existing.labels)
|
||||
nodes.remove(existing)
|
||||
nodes.add(merged)
|
||||
} else {
|
||||
@@ -42,15 +45,18 @@ class NodeDetailsList {
|
||||
}
|
||||
}
|
||||
|
||||
fun add(nodes: NodeDetailsList) {
|
||||
fun add(nodes: QuorumForLabels) {
|
||||
nodes.nodes.forEach { node -> this.add(node) }
|
||||
}
|
||||
|
||||
fun getNodes(): List<NodeDetails> {
|
||||
fun getAll(): List<QuorumItem> {
|
||||
return Collections.unmodifiableList(nodes)
|
||||
}
|
||||
|
||||
class NodeDetails(val quorum: Int, val labels: UpstreamsConfig.Labels) {
|
||||
/**
|
||||
* Details for a single element (upstream, node or aggregation)
|
||||
*/
|
||||
class QuorumItem(val quorum: Int, val labels: UpstreamsConfig.Labels) {
|
||||
companion object {
|
||||
}
|
||||
}
|
||||
@@ -13,10 +13,11 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.emeraldpay.dshackle.upstream
|
||||
package io.emeraldpay.dshackle.startup
|
||||
|
||||
import io.emeraldpay.dshackle.cache.Caches
|
||||
import io.emeraldpay.dshackle.cache.CachesEnabled
|
||||
import io.emeraldpay.dshackle.upstream.Upstream
|
||||
import io.emeraldpay.grpc.Chain
|
||||
|
||||
class UpstreamChange(
|
||||
@@ -18,6 +18,8 @@ package io.emeraldpay.dshackle.upstream
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import io.emeraldpay.dshackle.cache.*
|
||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||
import io.emeraldpay.dshackle.upstream.calls.AggregatedCallMethods
|
||||
import io.emeraldpay.dshackle.upstream.calls.CallMethods
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumHead
|
||||
import org.springframework.context.Lifecycle
|
||||
import reactor.core.Disposable
|
||||
|
||||
@@ -18,6 +18,9 @@ package io.emeraldpay.dshackle.upstream
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import io.emeraldpay.dshackle.cache.Caches
|
||||
import io.emeraldpay.dshackle.cache.CachesEnabled
|
||||
import io.emeraldpay.dshackle.startup.UpstreamChange
|
||||
import io.emeraldpay.dshackle.upstream.calls.CallMethods
|
||||
import io.emeraldpay.dshackle.upstream.calls.QuorumBasedMethods
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package io.emeraldpay.dshackle.upstream
|
||||
|
||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||
import io.emeraldpay.dshackle.upstream.calls.CallMethods
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.DirectEthereumApi
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumHead
|
||||
import reactor.core.publisher.Flux
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package io.emeraldpay.dshackle.upstream
|
||||
|
||||
import io.emeraldpay.dshackle.upstream.calls.CallMethods
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import reactor.core.publisher.Flux
|
||||
|
||||
|
||||
@@ -13,12 +13,15 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.emeraldpay.dshackle.upstream
|
||||
package io.emeraldpay.dshackle.upstream.calls
|
||||
|
||||
import io.emeraldpay.dshackle.quorum.CallQuorum
|
||||
import java.util.*
|
||||
import kotlin.collections.HashSet
|
||||
|
||||
/**
|
||||
* Aggregation over several parent configuration. It dispatches call to a first delegate that supports it.
|
||||
*/
|
||||
class AggregatedCallMethods(
|
||||
private val delegates: Collection<CallMethods>
|
||||
): CallMethods {
|
||||
@@ -31,24 +34,39 @@ class AggregatedCallMethods(
|
||||
allMethods = Collections.unmodifiableSet(buf)
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds first delegate that has Allowed that method and returns its Quorum
|
||||
*/
|
||||
override fun getQuorumFor(method: String): CallQuorum {
|
||||
return delegates.find {
|
||||
it.isAllowed(method)
|
||||
}?.getQuorumFor(method) ?: throw IllegalStateException("No quorum for $method")
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if ANY of delegates supports the method
|
||||
*/
|
||||
override fun isAllowed(method: String): Boolean {
|
||||
return delegates.any { it.isAllowed(method) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all available methods, accessible through at least one of delegates
|
||||
*/
|
||||
override fun getSupportedMethods(): Set<String> {
|
||||
return allMethods
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if there is at least one delegate that allows the method and it's hardcoded on that delegate
|
||||
*/
|
||||
override fun isHardcoded(method: String): Boolean {
|
||||
return delegates.any { it.isAllowed(method) && it.isHardcoded(method) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Executed the method on the first delegate that supports it as a hardcoded method
|
||||
*/
|
||||
override fun executeHardcoded(method: String): Any {
|
||||
return delegates.find {
|
||||
it.isAllowed(method) && it.isHardcoded(method)
|
||||
@@ -13,14 +13,37 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.emeraldpay.dshackle.upstream
|
||||
package io.emeraldpay.dshackle.upstream.calls
|
||||
|
||||
import io.emeraldpay.dshackle.quorum.CallQuorum
|
||||
|
||||
/**
|
||||
* Configuration for upstream calls
|
||||
*/
|
||||
interface CallMethods {
|
||||
|
||||
/**
|
||||
* @return CallQuorum configured for the specified method
|
||||
*/
|
||||
fun getQuorumFor(method: String): CallQuorum
|
||||
|
||||
/**
|
||||
* @return false is call for that method is not allowed. Allowed method may be also Hardcoded
|
||||
*/
|
||||
fun isAllowed(method: String): Boolean
|
||||
|
||||
/**
|
||||
* @return list of all allowed methods.
|
||||
*/
|
||||
fun getSupportedMethods(): Set<String>
|
||||
|
||||
/**
|
||||
* @return true if the method should not be executed on upstream, but accessed through this class
|
||||
*/
|
||||
fun isHardcoded(method: String): Boolean
|
||||
|
||||
/**
|
||||
* Read [supposed to be predefined] method from this config
|
||||
*/
|
||||
fun executeHardcoded(method: String): Any
|
||||
}
|
||||
@@ -13,12 +13,15 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.emeraldpay.dshackle.upstream
|
||||
package io.emeraldpay.dshackle.upstream.calls
|
||||
|
||||
import io.emeraldpay.dshackle.quorum.AlwaysQuorum
|
||||
import io.emeraldpay.dshackle.quorum.CallQuorum
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Configuration that uses [AlwaysQuorum] for all available methods. The methods list itself
|
||||
* is provided in constructor (or empty otherwise)
|
||||
*/
|
||||
class DirectCallMethods(private val methods: Set<String>) : CallMethods {
|
||||
|
||||
constructor(): this(emptySet())
|
||||
@@ -13,12 +13,17 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.emeraldpay.dshackle.upstream
|
||||
package io.emeraldpay.dshackle.upstream.calls
|
||||
|
||||
import io.emeraldpay.dshackle.quorum.AlwaysQuorum
|
||||
import io.emeraldpay.dshackle.quorum.CallQuorum
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Wrapper on top of another configuration, that may disable or enable additional methods on top of it.
|
||||
* If a new method enabled, then its Quorum will be [AlwaysQuorum]. For other methods it delegates all to the provided
|
||||
* parent config.
|
||||
*/
|
||||
class ManagedCallMethods(
|
||||
private val delegate: CallMethods,
|
||||
private val enabled: Set<String>,
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.emeraldpay.dshackle.upstream
|
||||
package io.emeraldpay.dshackle.upstream.calls
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import io.emeraldpay.dshackle.quorum.*
|
||||
@@ -22,6 +22,10 @@ import io.infinitape.etherjar.rpc.JacksonRpcConverter
|
||||
import io.infinitape.etherjar.rpc.RpcException
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Default configuration for Ethereum based RPC. Defines optimal Quorum strategies for different methods, and provides
|
||||
* hardcoded results for base methods, such as `net_version`, `web3_clientVersion` and similar
|
||||
*/
|
||||
class QuorumBasedMethods(
|
||||
private val objectMapper: ObjectMapper,
|
||||
private val chain: Chain
|
||||
@@ -18,7 +18,7 @@ package io.emeraldpay.dshackle.upstream.ethereum
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import io.emeraldpay.dshackle.Defaults
|
||||
import io.emeraldpay.dshackle.cache.Caches
|
||||
import io.emeraldpay.dshackle.upstream.CallMethods
|
||||
import io.emeraldpay.dshackle.upstream.calls.CallMethods
|
||||
import io.grpc.Status
|
||||
import io.grpc.StatusRuntimeException
|
||||
import io.infinitape.etherjar.domain.BlockHash
|
||||
|
||||
@@ -18,7 +18,10 @@ package io.emeraldpay.dshackle.upstream.ethereum
|
||||
import io.emeraldpay.dshackle.cache.Caches
|
||||
import io.emeraldpay.dshackle.cache.CachesEnabled
|
||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||
import io.emeraldpay.dshackle.startup.QuorumForLabels
|
||||
import io.emeraldpay.dshackle.upstream.*
|
||||
import io.emeraldpay.dshackle.upstream.calls.CallMethods
|
||||
import io.emeraldpay.dshackle.upstream.calls.DirectCallMethods
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.context.Lifecycle
|
||||
@@ -32,12 +35,12 @@ open class EthereumUpstream(
|
||||
private val api: DirectEthereumApi,
|
||||
private val ethereumWs: EthereumWs? = null,
|
||||
private val options: UpstreamsConfig.Options,
|
||||
val node: NodeDetailsList.NodeDetails,
|
||||
val node: QuorumForLabels.QuorumItem,
|
||||
private val targets: CallMethods
|
||||
): DefaultUpstream(), CachesEnabled, Lifecycle {
|
||||
|
||||
constructor(id: String, chain: Chain, api: DirectEthereumApi): this(id, chain, api, null,
|
||||
UpstreamsConfig.Options.getDefaults(), NodeDetailsList.NodeDetails(1, UpstreamsConfig.Labels()),
|
||||
UpstreamsConfig.Options.getDefaults(), QuorumForLabels.QuorumItem(1, UpstreamsConfig.Labels()),
|
||||
DirectCallMethods())
|
||||
|
||||
|
||||
|
||||
@@ -24,13 +24,15 @@ import io.emeraldpay.dshackle.Defaults
|
||||
import io.emeraldpay.dshackle.cache.Caches
|
||||
import io.emeraldpay.dshackle.cache.CachesEnabled
|
||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||
import io.emeraldpay.dshackle.startup.QuorumForLabels
|
||||
import io.emeraldpay.dshackle.upstream.*
|
||||
import io.emeraldpay.dshackle.upstream.calls.CallMethods
|
||||
import io.emeraldpay.dshackle.upstream.calls.DirectCallMethods
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.DefaultEthereumHead
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.DirectEthereumApi
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumHead
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import io.infinitape.etherjar.domain.BlockHash
|
||||
import io.infinitape.etherjar.domain.TransactionId
|
||||
import io.infinitape.etherjar.rpc.*
|
||||
import io.infinitape.etherjar.rpc.emerald.ReactorEmeraldClient
|
||||
import io.infinitape.etherjar.rpc.json.BlockJson
|
||||
@@ -62,7 +64,7 @@ open class GrpcUpstream(
|
||||
private var caches: Caches? = null
|
||||
|
||||
private val options = UpstreamsConfig.Options.getDefaults()
|
||||
private val nodes = AtomicReference<NodeDetailsList>(NodeDetailsList())
|
||||
private val nodes = AtomicReference<QuorumForLabels>(QuorumForLabels())
|
||||
private val head = DefaultEthereumHead()
|
||||
private var targets: CallMethods? = null
|
||||
private var headSubscription: Disposable? = null
|
||||
@@ -148,10 +150,10 @@ open class GrpcUpstream(
|
||||
|
||||
fun init(conf: BlockchainOuterClass.DescribeChain) {
|
||||
targets = DirectCallMethods(conf.supportedMethodsList.toSet())
|
||||
val nodes = NodeDetailsList()
|
||||
val nodes = QuorumForLabels()
|
||||
val allLabels = ArrayList<UpstreamsConfig.Labels>()
|
||||
conf.nodesList.forEach { remoteNode ->
|
||||
val node = NodeDetailsList.NodeDetails(remoteNode.quorum,
|
||||
val node = QuorumForLabels.QuorumItem(remoteNode.quorum,
|
||||
remoteNode.labelsList.let { provided ->
|
||||
val labels = UpstreamsConfig.Labels()
|
||||
provided.forEach {
|
||||
@@ -176,7 +178,7 @@ open class GrpcUpstream(
|
||||
)
|
||||
}
|
||||
|
||||
fun getNodes(): NodeDetailsList {
|
||||
fun getNodes(): QuorumForLabels {
|
||||
return nodes.get()
|
||||
}
|
||||
|
||||
@@ -191,7 +193,7 @@ open class GrpcUpstream(
|
||||
}
|
||||
|
||||
override fun isAvailable(): Boolean {
|
||||
return getStatus() == UpstreamAvailability.OK && head.getCurrent() != null && nodes.get().getNodes().any {
|
||||
return getStatus() == UpstreamAvailability.OK && head.getCurrent() != null && nodes.get().getAll().any {
|
||||
it.quorum > 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ import io.emeraldpay.dshackle.Defaults
|
||||
import io.emeraldpay.dshackle.FileResolver
|
||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||
import io.emeraldpay.dshackle.upstream.UpstreamAvailability
|
||||
import io.emeraldpay.dshackle.upstream.UpstreamChange
|
||||
import io.emeraldpay.dshackle.startup.UpstreamChange
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import io.grpc.ManagedChannelBuilder
|
||||
import io.grpc.netty.NettyChannelBuilder
|
||||
@@ -36,7 +36,6 @@ import reactor.core.publisher.Flux
|
||||
import java.net.ConnectException
|
||||
import java.time.Duration
|
||||
import java.util.*
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
import kotlin.concurrent.withLock
|
||||
|
||||
@@ -18,13 +18,11 @@ package io.emeraldpay.dshackle.test
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.google.protobuf.ByteString
|
||||
import io.emeraldpay.api.proto.BlockchainOuterClass
|
||||
import io.emeraldpay.dshackle.upstream.DirectCallMethods
|
||||
import io.emeraldpay.dshackle.upstream.calls.DirectCallMethods
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.DirectEthereumApi
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import io.grpc.stub.StreamObserver
|
||||
import io.infinitape.etherjar.rpc.ReactorRpcClient
|
||||
import io.infinitape.etherjar.rpc.RpcClient
|
||||
import io.infinitape.etherjar.rpc.RpcException
|
||||
import io.infinitape.etherjar.rpc.RpcResponseError
|
||||
import io.infinitape.etherjar.rpc.json.ResponseJson
|
||||
import org.jetbrains.annotations.NotNull
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
package io.emeraldpay.dshackle.test
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import io.emeraldpay.dshackle.upstream.DirectCallMethods
|
||||
import io.emeraldpay.dshackle.upstream.calls.DirectCallMethods
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.DirectEthereumApi
|
||||
import io.infinitape.etherjar.rpc.ReactorBatch
|
||||
import io.infinitape.etherjar.rpc.ReactorRpcClient
|
||||
@@ -25,8 +25,6 @@ import io.infinitape.etherjar.rpc.RpcCallResponse
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Mono
|
||||
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
class EthereumApiStub extends DirectEthereumApi {
|
||||
|
||||
private String id
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
package io.emeraldpay.dshackle.test
|
||||
|
||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||
import io.emeraldpay.dshackle.upstream.CallMethods
|
||||
import io.emeraldpay.dshackle.upstream.NodeDetailsList
|
||||
import io.emeraldpay.dshackle.upstream.QuorumBasedMethods
|
||||
import io.emeraldpay.dshackle.upstream.calls.CallMethods
|
||||
import io.emeraldpay.dshackle.startup.QuorumForLabels
|
||||
import io.emeraldpay.dshackle.upstream.calls.QuorumBasedMethods
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.DirectEthereumApi
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumHead
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumUpstream
|
||||
@@ -46,7 +46,7 @@ class EthereumUpstreamMock extends EthereumUpstream {
|
||||
|
||||
EthereumUpstreamMock(@NotNull String id, @NotNull Chain chain, @NotNull DirectEthereumApi api, CallMethods methods) {
|
||||
super(id, chain, api, null,
|
||||
UpstreamsConfig.Options.getDefaults(), new NodeDetailsList.NodeDetails(1, new UpstreamsConfig.Labels()),
|
||||
UpstreamsConfig.Options.getDefaults(), new QuorumForLabels.QuorumItem(1, new UpstreamsConfig.Labels()),
|
||||
methods)
|
||||
setLag(0)
|
||||
setStatus(UpstreamAvailability.OK)
|
||||
|
||||
@@ -21,16 +21,13 @@ import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule
|
||||
import io.emeraldpay.dshackle.cache.Caches
|
||||
import io.emeraldpay.dshackle.upstream.AggregatedUpstream
|
||||
import io.emeraldpay.dshackle.upstream.CallMethods
|
||||
import io.emeraldpay.dshackle.upstream.ChainUpstreams
|
||||
import io.emeraldpay.dshackle.upstream.DirectCallMethods
|
||||
import io.emeraldpay.dshackle.upstream.QuorumBasedMethods
|
||||
import io.emeraldpay.dshackle.upstream.calls.DirectCallMethods
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.DirectEthereumApi
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumUpstream
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import io.infinitape.etherjar.rpc.JacksonRpcConverter
|
||||
import io.infinitape.etherjar.rpc.ReactorRpcClient
|
||||
import io.infinitape.etherjar.rpc.RpcClient
|
||||
|
||||
import java.text.SimpleDateFormat
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ package io.emeraldpay.dshackle.test
|
||||
import io.emeraldpay.dshackle.cache.Caches
|
||||
import io.emeraldpay.dshackle.upstream.AggregatedUpstream
|
||||
import io.emeraldpay.dshackle.upstream.ChainUpstreams
|
||||
import io.emeraldpay.dshackle.upstream.QuorumBasedMethods
|
||||
import io.emeraldpay.dshackle.upstream.calls.QuorumBasedMethods
|
||||
import io.emeraldpay.dshackle.upstream.Upstream
|
||||
import io.emeraldpay.dshackle.upstream.Upstreams
|
||||
import io.emeraldpay.grpc.Chain
|
||||
|
||||
@@ -19,6 +19,7 @@ import io.emeraldpay.dshackle.cache.Caches
|
||||
import io.emeraldpay.dshackle.quorum.AlwaysQuorum
|
||||
import io.emeraldpay.dshackle.test.EthereumUpstreamMock
|
||||
import io.emeraldpay.dshackle.test.TestingCommons
|
||||
import io.emeraldpay.dshackle.upstream.calls.DirectCallMethods
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.DirectEthereumApi
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import spock.lang.Specification
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.emeraldpay.dshackle.upstream
|
||||
|
||||
import io.emeraldpay.dshackle.startup.UpstreamChange
|
||||
import io.emeraldpay.dshackle.test.EthereumUpstreamMock
|
||||
import io.emeraldpay.dshackle.test.TestingCommons
|
||||
import io.emeraldpay.grpc.Chain
|
||||
|
||||
@@ -16,8 +16,10 @@
|
||||
package io.emeraldpay.dshackle.upstream
|
||||
|
||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||
import io.emeraldpay.dshackle.startup.QuorumForLabels
|
||||
import io.emeraldpay.dshackle.test.EthereumApiStub
|
||||
import io.emeraldpay.dshackle.test.TestingCommons
|
||||
import io.emeraldpay.dshackle.upstream.calls.QuorumBasedMethods
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.DirectEthereumApi
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumUpstream
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumWs
|
||||
@@ -50,7 +52,7 @@ class FilteredApisSpec extends Specification {
|
||||
new DirectEthereumApi(rpcClient, null, objectMapper, ethereumTargets),
|
||||
(EthereumWs) null,
|
||||
new UpstreamsConfig.Options(),
|
||||
new NodeDetailsList.NodeDetails(1, UpstreamsConfig.Labels.fromMap(it)),
|
||||
new QuorumForLabels.QuorumItem(1, UpstreamsConfig.Labels.fromMap(it)),
|
||||
ethereumTargets
|
||||
)
|
||||
}
|
||||
|
||||
@@ -16,49 +16,50 @@
|
||||
package io.emeraldpay.dshackle.upstream
|
||||
|
||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||
import io.emeraldpay.dshackle.startup.QuorumForLabels
|
||||
import org.codehaus.groovy.runtime.DefaultGroovyMethods
|
||||
import spock.lang.Specification
|
||||
|
||||
class NodeDetailsListSpec extends Specification {
|
||||
class QuorumForLabelsSpec extends Specification {
|
||||
|
||||
def "Adds new node"() {
|
||||
setup:
|
||||
def list = new NodeDetailsList()
|
||||
def list = new QuorumForLabels()
|
||||
when:
|
||||
list.add(new NodeDetailsList.NodeDetails(1, asLabels([foo: "bar"])))
|
||||
list.add(new QuorumForLabels.QuorumItem(1, asLabels([foo: "bar"])))
|
||||
then:
|
||||
list.nodes.size() == 1
|
||||
with(list.nodes.get(0)) {
|
||||
list.all.size() == 1
|
||||
with(list.all.get(0)) {
|
||||
quorum == 1
|
||||
DefaultGroovyMethods.equals(labels, [foo: "bar"])
|
||||
}
|
||||
|
||||
when:
|
||||
list.add(new NodeDetailsList.NodeDetails(2, asLabels([foo: "not-bar"])))
|
||||
list.add(new QuorumForLabels.QuorumItem(2, asLabels([foo: "not-bar"])))
|
||||
then:
|
||||
list.nodes.size() == 2
|
||||
with(list.nodes.get(0)) {
|
||||
list.all.size() == 2
|
||||
with(list.all.get(0)) {
|
||||
quorum == 1
|
||||
DefaultGroovyMethods.equals(labels, [foo: "bar"])
|
||||
}
|
||||
with(list.nodes.get(1)) {
|
||||
with(list.all.get(1)) {
|
||||
quorum == 2
|
||||
DefaultGroovyMethods.equals(labels, [foo: "not-bar"])
|
||||
}
|
||||
|
||||
when:
|
||||
list.add(new NodeDetailsList.NodeDetails(1, asLabels([foo: "bar", baz: "baz"])))
|
||||
list.add(new QuorumForLabels.QuorumItem(1, asLabels([foo: "bar", baz: "baz"])))
|
||||
then:
|
||||
list.nodes.size() == 3
|
||||
with(list.nodes.get(0)) {
|
||||
list.all.size() == 3
|
||||
with(list.all.get(0)) {
|
||||
quorum == 1
|
||||
DefaultGroovyMethods.equals(labels, [foo: "bar"])
|
||||
}
|
||||
with(list.nodes.get(1)) {
|
||||
with(list.all.get(1)) {
|
||||
quorum == 2
|
||||
DefaultGroovyMethods.equals(labels, [foo: "not-bar"])
|
||||
}
|
||||
with(list.nodes.get(2)) {
|
||||
with(list.all.get(2)) {
|
||||
quorum == 1
|
||||
DefaultGroovyMethods.equals(labels, [foo: "bar", baz: "baz"])
|
||||
}
|
||||
@@ -66,19 +67,19 @@ class NodeDetailsListSpec extends Specification {
|
||||
|
||||
def "Updates existing node"() {
|
||||
setup:
|
||||
def list = new NodeDetailsList()
|
||||
list.add(new NodeDetailsList.NodeDetails(1, asLabels([foo: "bar"])))
|
||||
list.add(new NodeDetailsList.NodeDetails(1, asLabels([baz: "true"])))
|
||||
def list = new QuorumForLabels()
|
||||
list.add(new QuorumForLabels.QuorumItem(1, asLabels([foo: "bar"])))
|
||||
list.add(new QuorumForLabels.QuorumItem(1, asLabels([baz: "true"])))
|
||||
|
||||
when:
|
||||
list.add(new NodeDetailsList.NodeDetails(2, asLabels([baz: "true"])))
|
||||
list.add(new QuorumForLabels.QuorumItem(2, asLabels([baz: "true"])))
|
||||
then:
|
||||
list.nodes.size() == 2
|
||||
with(list.nodes.get(0)) {
|
||||
list.all.size() == 2
|
||||
with(list.all.get(0)) {
|
||||
quorum == 1
|
||||
DefaultGroovyMethods.equals(labels, [foo: "bar"])
|
||||
}
|
||||
with(list.nodes.get(1)) {
|
||||
with(list.all.get(1)) {
|
||||
quorum == 3
|
||||
DefaultGroovyMethods.equals(labels, [baz: "true"])
|
||||
}
|
||||
@@ -86,23 +87,23 @@ class NodeDetailsListSpec extends Specification {
|
||||
|
||||
def "Applies all from another list"() {
|
||||
setup:
|
||||
def list1 = new NodeDetailsList()
|
||||
list1.add(new NodeDetailsList.NodeDetails(1, asLabels([foo: "bar"])))
|
||||
list1.add(new NodeDetailsList.NodeDetails(2, asLabels([baz: "true"])))
|
||||
list1.add(new NodeDetailsList.NodeDetails(3, asLabels([baz: "true", bar: "bar"])))
|
||||
def list1 = new QuorumForLabels()
|
||||
list1.add(new QuorumForLabels.QuorumItem(1, asLabels([foo: "bar"])))
|
||||
list1.add(new QuorumForLabels.QuorumItem(2, asLabels([baz: "true"])))
|
||||
list1.add(new QuorumForLabels.QuorumItem(3, asLabels([baz: "true", bar: "bar"])))
|
||||
|
||||
def list2 = new NodeDetailsList()
|
||||
list1.add(new NodeDetailsList.NodeDetails(4, asLabels([foo: "bar"])))
|
||||
list1.add(new NodeDetailsList.NodeDetails(5, asLabels([baz: "true", bar: "bar"])))
|
||||
list1.add(new NodeDetailsList.NodeDetails(6, asLabels([bar: "bar"])))
|
||||
def list2 = new QuorumForLabels()
|
||||
list1.add(new QuorumForLabels.QuorumItem(4, asLabels([foo: "bar"])))
|
||||
list1.add(new QuorumForLabels.QuorumItem(5, asLabels([baz: "true", bar: "bar"])))
|
||||
list1.add(new QuorumForLabels.QuorumItem(6, asLabels([bar: "bar"])))
|
||||
|
||||
def list = new NodeDetailsList()
|
||||
def list = new QuorumForLabels()
|
||||
when:
|
||||
list.add(list1)
|
||||
list.add(list2)
|
||||
def nodes = list.nodes.toSorted { it.quorum }
|
||||
def nodes = list.all.toSorted { it.quorum }
|
||||
then:
|
||||
list.nodes.size() == 4
|
||||
list.all.size() == 4
|
||||
with(nodes.get(0)) {
|
||||
quorum == 2
|
||||
DefaultGroovyMethods.equals(labels, [baz: "true"])
|
||||
@@ -13,9 +13,12 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.emeraldpay.dshackle.upstream
|
||||
package io.emeraldpay.dshackle.upstream.calls
|
||||
|
||||
import io.emeraldpay.dshackle.quorum.AlwaysQuorum
|
||||
import io.emeraldpay.dshackle.upstream.calls.AggregatedCallMethods
|
||||
import io.emeraldpay.dshackle.upstream.calls.CallMethods
|
||||
import io.emeraldpay.dshackle.upstream.calls.DirectCallMethods
|
||||
import spock.lang.Specification
|
||||
|
||||
class AggregatedCallMethodsSpec extends Specification {
|
||||
@@ -13,9 +13,11 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.emeraldpay.dshackle.upstream
|
||||
package io.emeraldpay.dshackle.upstream.calls
|
||||
|
||||
import io.emeraldpay.dshackle.quorum.AlwaysQuorum
|
||||
import io.emeraldpay.dshackle.upstream.calls.DirectCallMethods
|
||||
import io.emeraldpay.dshackle.upstream.calls.ManagedCallMethods
|
||||
import spock.lang.Specification
|
||||
|
||||
class ManagedCallMethodsSpec extends Specification {
|
||||
@@ -16,7 +16,7 @@
|
||||
package io.emeraldpay.dshackle.upstream.ethereum
|
||||
|
||||
import io.emeraldpay.dshackle.test.TestingCommons
|
||||
import io.emeraldpay.dshackle.upstream.DirectCallMethods
|
||||
import io.emeraldpay.dshackle.upstream.calls.DirectCallMethods
|
||||
import io.infinitape.etherjar.rpc.ReactorRpcClient
|
||||
import io.infinitape.etherjar.rpc.RpcException
|
||||
import io.infinitape.etherjar.rpc.RpcResponseError
|
||||
|
||||
@@ -22,22 +22,17 @@ import io.emeraldpay.api.proto.BlockchainOuterClass
|
||||
import io.emeraldpay.api.proto.Common
|
||||
import io.emeraldpay.dshackle.test.MockServer
|
||||
import io.emeraldpay.dshackle.test.TestingCommons
|
||||
import io.emeraldpay.dshackle.upstream.QuorumBasedMethods
|
||||
import io.emeraldpay.dshackle.upstream.UpstreamAvailability
|
||||
import io.emeraldpay.dshackle.upstream.grpc.GrpcUpstream
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import io.grpc.stub.StreamObserver
|
||||
import io.infinitape.etherjar.domain.BlockHash
|
||||
import io.infinitape.etherjar.rpc.JacksonRpcConverter
|
||||
import io.infinitape.etherjar.rpc.ReactorRpcClient
|
||||
import io.infinitape.etherjar.rpc.emerald.ReactorEmeraldClient
|
||||
import io.infinitape.etherjar.rpc.json.BlockJson
|
||||
import reactor.test.StepVerifier
|
||||
import spock.lang.Specification
|
||||
|
||||
import java.time.Duration
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
class GrpcUpstreamSpec extends Specification {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user