solution: refactoring

This commit is contained in:
Igor Artamonov
2020-02-24 22:14:24 -05:00
parent b255bed3a1
commit 2816b5b8fc
30 changed files with 158 additions and 86 deletions

View File

@@ -17,6 +17,7 @@ package io.emeraldpay.dshackle.rpc
import io.emeraldpay.api.proto.BlockchainOuterClass import io.emeraldpay.api.proto.BlockchainOuterClass
import io.emeraldpay.api.proto.Common import io.emeraldpay.api.proto.Common
import io.emeraldpay.dshackle.startup.QuorumForLabels
import io.emeraldpay.dshackle.upstream.* import io.emeraldpay.dshackle.upstream.*
import io.emeraldpay.dshackle.upstream.ethereum.EthereumUpstream import io.emeraldpay.dshackle.upstream.ethereum.EthereumUpstream
import io.emeraldpay.dshackle.upstream.grpc.GrpcUpstream import io.emeraldpay.dshackle.upstream.grpc.GrpcUpstream
@@ -43,13 +44,13 @@ class Describe(
.setStatus(status) .setStatus(status)
chainUpstreams.getAll().let { ups -> chainUpstreams.getAll().let { ups ->
ups.forEach { up -> ups.forEach { up ->
val nodes = NodeDetailsList() val nodes = QuorumForLabels()
if (up is EthereumUpstream) { if (up is EthereumUpstream) {
nodes.add(up.node) nodes.add(up.node)
} else if (up is GrpcUpstream) { } else if (up is GrpcUpstream) {
nodes.add(up.getNodes()) nodes.add(up.getNodes())
} }
nodes.getNodes().forEach { node -> nodes.getAll().forEach { node ->
val nodeDetails = BlockchainOuterClass.NodeDetails.newBuilder() val nodeDetails = BlockchainOuterClass.NodeDetails.newBuilder()
.setQuorum(node.quorum) .setQuorum(node.quorum)
.addAllLabels(node.labels.entries.map { label -> .addAllLabels(node.labels.entries.map { label ->

View File

@@ -13,12 +13,14 @@
* 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 package io.emeraldpay.dshackle.startup
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import io.emeraldpay.dshackle.FileResolver import io.emeraldpay.dshackle.FileResolver
import io.emeraldpay.dshackle.config.UpstreamsConfig import io.emeraldpay.dshackle.config.UpstreamsConfig
import io.emeraldpay.dshackle.config.UpstreamsConfigReader 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.DirectEthereumApi
import io.emeraldpay.dshackle.upstream.ethereum.EthereumUpstream import io.emeraldpay.dshackle.upstream.ethereum.EthereumUpstream
import io.emeraldpay.dshackle.upstream.ethereum.EthereumWs import io.emeraldpay.dshackle.upstream.ethereum.EthereumWs
@@ -172,7 +174,7 @@ open class ConfiguredUpstreams(
val ethereumUpstream = EthereumUpstream( val ethereumUpstream = EthereumUpstream(
config.id!!, config.id!!,
chain, rpcApi!!, wsApi, options, chain, rpcApi!!, wsApi, options,
NodeDetailsList.NodeDetails(1, config.labels), QuorumForLabels.QuorumItem(1, config.labels),
methods) methods)
ethereumUpstream.start() ethereumUpstream.start()
currentUpstreams.update(UpstreamChange(chain, ethereumUpstream, UpstreamChange.ChangeType.ADDED)) currentUpstreams.update(UpstreamChange(chain, ethereumUpstream, UpstreamChange.ChangeType.ADDED))

View File

@@ -13,7 +13,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 package io.emeraldpay.dshackle.startup
import io.emeraldpay.dshackle.config.UpstreamsConfig import io.emeraldpay.dshackle.config.UpstreamsConfig
import java.util.* import java.util.*
@@ -22,17 +22,20 @@ import kotlin.collections.ArrayList
import kotlin.concurrent.read import kotlin.concurrent.read
import kotlin.concurrent.write 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 lock = ReentrantReadWriteLock()
private val nodes = ArrayList<NodeDetails>() private val nodes = ArrayList<QuorumItem>()
fun add(node: NodeDetails) { fun add(node: QuorumItem) {
lock.read { lock.read {
val existing = nodes.find { it.labels == node.labels } val existing = nodes.find { it.labels == node.labels }
lock.write { lock.write {
if (existing != null) { 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.remove(existing)
nodes.add(merged) nodes.add(merged)
} else { } else {
@@ -42,15 +45,18 @@ class NodeDetailsList {
} }
} }
fun add(nodes: NodeDetailsList) { fun add(nodes: QuorumForLabels) {
nodes.nodes.forEach { node -> this.add(node) } nodes.nodes.forEach { node -> this.add(node) }
} }
fun getNodes(): List<NodeDetails> { fun getAll(): List<QuorumItem> {
return Collections.unmodifiableList(nodes) 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 { companion object {
} }
} }

View File

@@ -13,10 +13,11 @@
* 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 package io.emeraldpay.dshackle.startup
import io.emeraldpay.dshackle.cache.Caches import io.emeraldpay.dshackle.cache.Caches
import io.emeraldpay.dshackle.cache.CachesEnabled import io.emeraldpay.dshackle.cache.CachesEnabled
import io.emeraldpay.dshackle.upstream.Upstream
import io.emeraldpay.grpc.Chain import io.emeraldpay.grpc.Chain
class UpstreamChange( class UpstreamChange(

View File

@@ -18,6 +18,8 @@ package io.emeraldpay.dshackle.upstream
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import io.emeraldpay.dshackle.cache.* import io.emeraldpay.dshackle.cache.*
import io.emeraldpay.dshackle.config.UpstreamsConfig 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 io.emeraldpay.dshackle.upstream.ethereum.EthereumHead
import org.springframework.context.Lifecycle import org.springframework.context.Lifecycle
import reactor.core.Disposable import reactor.core.Disposable

View File

@@ -18,6 +18,9 @@ package io.emeraldpay.dshackle.upstream
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import io.emeraldpay.dshackle.cache.Caches import io.emeraldpay.dshackle.cache.Caches
import io.emeraldpay.dshackle.cache.CachesEnabled 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 io.emeraldpay.grpc.Chain
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Autowired

View File

@@ -16,6 +16,7 @@
package io.emeraldpay.dshackle.upstream package io.emeraldpay.dshackle.upstream
import io.emeraldpay.dshackle.config.UpstreamsConfig 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.DirectEthereumApi
import io.emeraldpay.dshackle.upstream.ethereum.EthereumHead import io.emeraldpay.dshackle.upstream.ethereum.EthereumHead
import reactor.core.publisher.Flux import reactor.core.publisher.Flux

View File

@@ -15,6 +15,7 @@
*/ */
package io.emeraldpay.dshackle.upstream package io.emeraldpay.dshackle.upstream
import io.emeraldpay.dshackle.upstream.calls.CallMethods
import io.emeraldpay.grpc.Chain import io.emeraldpay.grpc.Chain
import reactor.core.publisher.Flux import reactor.core.publisher.Flux

View File

@@ -13,12 +13,15 @@
* 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 package io.emeraldpay.dshackle.upstream.calls
import io.emeraldpay.dshackle.quorum.CallQuorum import io.emeraldpay.dshackle.quorum.CallQuorum
import java.util.* import java.util.*
import kotlin.collections.HashSet import kotlin.collections.HashSet
/**
* Aggregation over several parent configuration. It dispatches call to a first delegate that supports it.
*/
class AggregatedCallMethods( class AggregatedCallMethods(
private val delegates: Collection<CallMethods> private val delegates: Collection<CallMethods>
): CallMethods { ): CallMethods {
@@ -31,24 +34,39 @@ class AggregatedCallMethods(
allMethods = Collections.unmodifiableSet(buf) allMethods = Collections.unmodifiableSet(buf)
} }
/**
* Finds first delegate that has Allowed that method and returns its Quorum
*/
override fun getQuorumFor(method: String): CallQuorum { override fun getQuorumFor(method: String): CallQuorum {
return delegates.find { return delegates.find {
it.isAllowed(method) it.isAllowed(method)
}?.getQuorumFor(method) ?: throw IllegalStateException("No quorum for $method") }?.getQuorumFor(method) ?: throw IllegalStateException("No quorum for $method")
} }
/**
* Checks if ANY of delegates supports the method
*/
override fun isAllowed(method: String): Boolean { override fun isAllowed(method: String): Boolean {
return delegates.any { it.isAllowed(method) } return delegates.any { it.isAllowed(method) }
} }
/**
* Returns all available methods, accessible through at least one of delegates
*/
override fun getSupportedMethods(): Set<String> { override fun getSupportedMethods(): Set<String> {
return allMethods 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 { override fun isHardcoded(method: String): Boolean {
return delegates.any { it.isAllowed(method) && it.isHardcoded(method) } 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 { override fun executeHardcoded(method: String): Any {
return delegates.find { return delegates.find {
it.isAllowed(method) && it.isHardcoded(method) it.isAllowed(method) && it.isHardcoded(method)

View File

@@ -13,14 +13,37 @@
* 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 package io.emeraldpay.dshackle.upstream.calls
import io.emeraldpay.dshackle.quorum.CallQuorum import io.emeraldpay.dshackle.quorum.CallQuorum
/**
* Configuration for upstream calls
*/
interface CallMethods { interface CallMethods {
/**
* @return CallQuorum configured for the specified method
*/
fun getQuorumFor(method: String): CallQuorum 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 fun isAllowed(method: String): Boolean
/**
* @return list of all allowed methods.
*/
fun getSupportedMethods(): Set<String> 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 fun isHardcoded(method: String): Boolean
/**
* Read [supposed to be predefined] method from this config
*/
fun executeHardcoded(method: String): Any fun executeHardcoded(method: String): Any
} }

View File

@@ -13,12 +13,15 @@
* 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 package io.emeraldpay.dshackle.upstream.calls
import io.emeraldpay.dshackle.quorum.AlwaysQuorum import io.emeraldpay.dshackle.quorum.AlwaysQuorum
import io.emeraldpay.dshackle.quorum.CallQuorum 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 { class DirectCallMethods(private val methods: Set<String>) : CallMethods {
constructor(): this(emptySet()) constructor(): this(emptySet())

View File

@@ -13,12 +13,17 @@
* 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 package io.emeraldpay.dshackle.upstream.calls
import io.emeraldpay.dshackle.quorum.AlwaysQuorum import io.emeraldpay.dshackle.quorum.AlwaysQuorum
import io.emeraldpay.dshackle.quorum.CallQuorum import io.emeraldpay.dshackle.quorum.CallQuorum
import java.util.* 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( class ManagedCallMethods(
private val delegate: CallMethods, private val delegate: CallMethods,
private val enabled: Set<String>, private val enabled: Set<String>,

View File

@@ -13,7 +13,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 package io.emeraldpay.dshackle.upstream.calls
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import io.emeraldpay.dshackle.quorum.* import io.emeraldpay.dshackle.quorum.*
@@ -22,6 +22,10 @@ import io.infinitape.etherjar.rpc.JacksonRpcConverter
import io.infinitape.etherjar.rpc.RpcException import io.infinitape.etherjar.rpc.RpcException
import java.util.* 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( class QuorumBasedMethods(
private val objectMapper: ObjectMapper, private val objectMapper: ObjectMapper,
private val chain: Chain private val chain: Chain

View File

@@ -18,7 +18,7 @@ package io.emeraldpay.dshackle.upstream.ethereum
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import io.emeraldpay.dshackle.Defaults import io.emeraldpay.dshackle.Defaults
import io.emeraldpay.dshackle.cache.Caches 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.Status
import io.grpc.StatusRuntimeException import io.grpc.StatusRuntimeException
import io.infinitape.etherjar.domain.BlockHash import io.infinitape.etherjar.domain.BlockHash

View File

@@ -18,7 +18,10 @@ package io.emeraldpay.dshackle.upstream.ethereum
import io.emeraldpay.dshackle.cache.Caches import io.emeraldpay.dshackle.cache.Caches
import io.emeraldpay.dshackle.cache.CachesEnabled import io.emeraldpay.dshackle.cache.CachesEnabled
import io.emeraldpay.dshackle.config.UpstreamsConfig import io.emeraldpay.dshackle.config.UpstreamsConfig
import io.emeraldpay.dshackle.startup.QuorumForLabels
import io.emeraldpay.dshackle.upstream.* 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 io.emeraldpay.grpc.Chain
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.context.Lifecycle import org.springframework.context.Lifecycle
@@ -32,12 +35,12 @@ open class EthereumUpstream(
private val api: DirectEthereumApi, private val api: DirectEthereumApi,
private val ethereumWs: EthereumWs? = null, private val ethereumWs: EthereumWs? = null,
private val options: UpstreamsConfig.Options, private val options: UpstreamsConfig.Options,
val node: NodeDetailsList.NodeDetails, val node: QuorumForLabels.QuorumItem,
private val targets: CallMethods private val targets: CallMethods
): DefaultUpstream(), CachesEnabled, Lifecycle { ): DefaultUpstream(), CachesEnabled, Lifecycle {
constructor(id: String, chain: Chain, api: DirectEthereumApi): this(id, chain, api, null, 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()) DirectCallMethods())

View File

@@ -24,13 +24,15 @@ import io.emeraldpay.dshackle.Defaults
import io.emeraldpay.dshackle.cache.Caches import io.emeraldpay.dshackle.cache.Caches
import io.emeraldpay.dshackle.cache.CachesEnabled import io.emeraldpay.dshackle.cache.CachesEnabled
import io.emeraldpay.dshackle.config.UpstreamsConfig import io.emeraldpay.dshackle.config.UpstreamsConfig
import io.emeraldpay.dshackle.startup.QuorumForLabels
import io.emeraldpay.dshackle.upstream.* 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.DefaultEthereumHead
import io.emeraldpay.dshackle.upstream.ethereum.DirectEthereumApi import io.emeraldpay.dshackle.upstream.ethereum.DirectEthereumApi
import io.emeraldpay.dshackle.upstream.ethereum.EthereumHead import io.emeraldpay.dshackle.upstream.ethereum.EthereumHead
import io.emeraldpay.grpc.Chain import io.emeraldpay.grpc.Chain
import io.infinitape.etherjar.domain.BlockHash import io.infinitape.etherjar.domain.BlockHash
import io.infinitape.etherjar.domain.TransactionId
import io.infinitape.etherjar.rpc.* import io.infinitape.etherjar.rpc.*
import io.infinitape.etherjar.rpc.emerald.ReactorEmeraldClient import io.infinitape.etherjar.rpc.emerald.ReactorEmeraldClient
import io.infinitape.etherjar.rpc.json.BlockJson import io.infinitape.etherjar.rpc.json.BlockJson
@@ -62,7 +64,7 @@ open class GrpcUpstream(
private var caches: Caches? = null private var caches: Caches? = null
private val options = UpstreamsConfig.Options.getDefaults() private val options = UpstreamsConfig.Options.getDefaults()
private val nodes = AtomicReference<NodeDetailsList>(NodeDetailsList()) private val nodes = AtomicReference<QuorumForLabels>(QuorumForLabels())
private val head = DefaultEthereumHead() private val head = DefaultEthereumHead()
private var targets: CallMethods? = null private var targets: CallMethods? = null
private var headSubscription: Disposable? = null private var headSubscription: Disposable? = null
@@ -148,10 +150,10 @@ open class GrpcUpstream(
fun init(conf: BlockchainOuterClass.DescribeChain) { fun init(conf: BlockchainOuterClass.DescribeChain) {
targets = DirectCallMethods(conf.supportedMethodsList.toSet()) targets = DirectCallMethods(conf.supportedMethodsList.toSet())
val nodes = NodeDetailsList() val nodes = QuorumForLabels()
val allLabels = ArrayList<UpstreamsConfig.Labels>() val allLabels = ArrayList<UpstreamsConfig.Labels>()
conf.nodesList.forEach { remoteNode -> conf.nodesList.forEach { remoteNode ->
val node = NodeDetailsList.NodeDetails(remoteNode.quorum, val node = QuorumForLabels.QuorumItem(remoteNode.quorum,
remoteNode.labelsList.let { provided -> remoteNode.labelsList.let { provided ->
val labels = UpstreamsConfig.Labels() val labels = UpstreamsConfig.Labels()
provided.forEach { provided.forEach {
@@ -176,7 +178,7 @@ open class GrpcUpstream(
) )
} }
fun getNodes(): NodeDetailsList { fun getNodes(): QuorumForLabels {
return nodes.get() return nodes.get()
} }
@@ -191,7 +193,7 @@ open class GrpcUpstream(
} }
override fun isAvailable(): Boolean { 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 it.quorum > 0
} }
} }

View File

@@ -22,7 +22,7 @@ import io.emeraldpay.dshackle.Defaults
import io.emeraldpay.dshackle.FileResolver import io.emeraldpay.dshackle.FileResolver
import io.emeraldpay.dshackle.config.UpstreamsConfig import io.emeraldpay.dshackle.config.UpstreamsConfig
import io.emeraldpay.dshackle.upstream.UpstreamAvailability 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.emeraldpay.grpc.Chain
import io.grpc.ManagedChannelBuilder import io.grpc.ManagedChannelBuilder
import io.grpc.netty.NettyChannelBuilder import io.grpc.netty.NettyChannelBuilder
@@ -36,7 +36,6 @@ import reactor.core.publisher.Flux
import java.net.ConnectException import java.net.ConnectException
import java.time.Duration import java.time.Duration
import java.util.* import java.util.*
import java.util.concurrent.Executors
import java.util.concurrent.atomic.AtomicReference import java.util.concurrent.atomic.AtomicReference
import java.util.concurrent.locks.ReentrantLock import java.util.concurrent.locks.ReentrantLock
import kotlin.concurrent.withLock import kotlin.concurrent.withLock

View File

@@ -18,13 +18,11 @@ package io.emeraldpay.dshackle.test
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import com.google.protobuf.ByteString import com.google.protobuf.ByteString
import io.emeraldpay.api.proto.BlockchainOuterClass 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.dshackle.upstream.ethereum.DirectEthereumApi
import io.emeraldpay.grpc.Chain import io.emeraldpay.grpc.Chain
import io.grpc.stub.StreamObserver import io.grpc.stub.StreamObserver
import io.infinitape.etherjar.rpc.ReactorRpcClient 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.RpcResponseError
import io.infinitape.etherjar.rpc.json.ResponseJson import io.infinitape.etherjar.rpc.json.ResponseJson
import org.jetbrains.annotations.NotNull import org.jetbrains.annotations.NotNull

View File

@@ -16,7 +16,7 @@
package io.emeraldpay.dshackle.test package io.emeraldpay.dshackle.test
import com.fasterxml.jackson.databind.ObjectMapper 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.emeraldpay.dshackle.upstream.ethereum.DirectEthereumApi
import io.infinitape.etherjar.rpc.ReactorBatch import io.infinitape.etherjar.rpc.ReactorBatch
import io.infinitape.etherjar.rpc.ReactorRpcClient 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.Flux
import reactor.core.publisher.Mono import reactor.core.publisher.Mono
import java.util.concurrent.CompletableFuture
class EthereumApiStub extends DirectEthereumApi { class EthereumApiStub extends DirectEthereumApi {
private String id private String id

View File

@@ -16,9 +16,9 @@
package io.emeraldpay.dshackle.test package io.emeraldpay.dshackle.test
import io.emeraldpay.dshackle.config.UpstreamsConfig import io.emeraldpay.dshackle.config.UpstreamsConfig
import io.emeraldpay.dshackle.upstream.CallMethods import io.emeraldpay.dshackle.upstream.calls.CallMethods
import io.emeraldpay.dshackle.upstream.NodeDetailsList import io.emeraldpay.dshackle.startup.QuorumForLabels
import io.emeraldpay.dshackle.upstream.QuorumBasedMethods import io.emeraldpay.dshackle.upstream.calls.QuorumBasedMethods
import io.emeraldpay.dshackle.upstream.ethereum.DirectEthereumApi import io.emeraldpay.dshackle.upstream.ethereum.DirectEthereumApi
import io.emeraldpay.dshackle.upstream.ethereum.EthereumHead import io.emeraldpay.dshackle.upstream.ethereum.EthereumHead
import io.emeraldpay.dshackle.upstream.ethereum.EthereumUpstream 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) { EthereumUpstreamMock(@NotNull String id, @NotNull Chain chain, @NotNull DirectEthereumApi api, CallMethods methods) {
super(id, chain, api, null, 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) methods)
setLag(0) setLag(0)
setStatus(UpstreamAvailability.OK) setStatus(UpstreamAvailability.OK)

View File

@@ -21,16 +21,13 @@ import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.module.SimpleModule import com.fasterxml.jackson.databind.module.SimpleModule
import io.emeraldpay.dshackle.cache.Caches import io.emeraldpay.dshackle.cache.Caches
import io.emeraldpay.dshackle.upstream.AggregatedUpstream import io.emeraldpay.dshackle.upstream.AggregatedUpstream
import io.emeraldpay.dshackle.upstream.CallMethods
import io.emeraldpay.dshackle.upstream.ChainUpstreams import io.emeraldpay.dshackle.upstream.ChainUpstreams
import io.emeraldpay.dshackle.upstream.DirectCallMethods import io.emeraldpay.dshackle.upstream.calls.DirectCallMethods
import io.emeraldpay.dshackle.upstream.QuorumBasedMethods
import io.emeraldpay.dshackle.upstream.ethereum.DirectEthereumApi import io.emeraldpay.dshackle.upstream.ethereum.DirectEthereumApi
import io.emeraldpay.dshackle.upstream.ethereum.EthereumUpstream import io.emeraldpay.dshackle.upstream.ethereum.EthereumUpstream
import io.emeraldpay.grpc.Chain import io.emeraldpay.grpc.Chain
import io.infinitape.etherjar.rpc.JacksonRpcConverter import io.infinitape.etherjar.rpc.JacksonRpcConverter
import io.infinitape.etherjar.rpc.ReactorRpcClient import io.infinitape.etherjar.rpc.ReactorRpcClient
import io.infinitape.etherjar.rpc.RpcClient
import java.text.SimpleDateFormat import java.text.SimpleDateFormat

View File

@@ -18,7 +18,7 @@ package io.emeraldpay.dshackle.test
import io.emeraldpay.dshackle.cache.Caches import io.emeraldpay.dshackle.cache.Caches
import io.emeraldpay.dshackle.upstream.AggregatedUpstream import io.emeraldpay.dshackle.upstream.AggregatedUpstream
import io.emeraldpay.dshackle.upstream.ChainUpstreams 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.Upstream
import io.emeraldpay.dshackle.upstream.Upstreams import io.emeraldpay.dshackle.upstream.Upstreams
import io.emeraldpay.grpc.Chain import io.emeraldpay.grpc.Chain

View File

@@ -19,6 +19,7 @@ import io.emeraldpay.dshackle.cache.Caches
import io.emeraldpay.dshackle.quorum.AlwaysQuorum import io.emeraldpay.dshackle.quorum.AlwaysQuorum
import io.emeraldpay.dshackle.test.EthereumUpstreamMock import io.emeraldpay.dshackle.test.EthereumUpstreamMock
import io.emeraldpay.dshackle.test.TestingCommons import io.emeraldpay.dshackle.test.TestingCommons
import io.emeraldpay.dshackle.upstream.calls.DirectCallMethods
import io.emeraldpay.dshackle.upstream.ethereum.DirectEthereumApi import io.emeraldpay.dshackle.upstream.ethereum.DirectEthereumApi
import io.emeraldpay.grpc.Chain import io.emeraldpay.grpc.Chain
import spock.lang.Specification import spock.lang.Specification

View File

@@ -1,5 +1,6 @@
package io.emeraldpay.dshackle.upstream package io.emeraldpay.dshackle.upstream
import io.emeraldpay.dshackle.startup.UpstreamChange
import io.emeraldpay.dshackle.test.EthereumUpstreamMock import io.emeraldpay.dshackle.test.EthereumUpstreamMock
import io.emeraldpay.dshackle.test.TestingCommons import io.emeraldpay.dshackle.test.TestingCommons
import io.emeraldpay.grpc.Chain import io.emeraldpay.grpc.Chain

View File

@@ -16,8 +16,10 @@
package io.emeraldpay.dshackle.upstream package io.emeraldpay.dshackle.upstream
import io.emeraldpay.dshackle.config.UpstreamsConfig import io.emeraldpay.dshackle.config.UpstreamsConfig
import io.emeraldpay.dshackle.startup.QuorumForLabels
import io.emeraldpay.dshackle.test.EthereumApiStub import io.emeraldpay.dshackle.test.EthereumApiStub
import io.emeraldpay.dshackle.test.TestingCommons 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.DirectEthereumApi
import io.emeraldpay.dshackle.upstream.ethereum.EthereumUpstream import io.emeraldpay.dshackle.upstream.ethereum.EthereumUpstream
import io.emeraldpay.dshackle.upstream.ethereum.EthereumWs import io.emeraldpay.dshackle.upstream.ethereum.EthereumWs
@@ -50,7 +52,7 @@ class FilteredApisSpec extends Specification {
new DirectEthereumApi(rpcClient, null, objectMapper, ethereumTargets), new DirectEthereumApi(rpcClient, null, objectMapper, ethereumTargets),
(EthereumWs) null, (EthereumWs) null,
new UpstreamsConfig.Options(), new UpstreamsConfig.Options(),
new NodeDetailsList.NodeDetails(1, UpstreamsConfig.Labels.fromMap(it)), new QuorumForLabels.QuorumItem(1, UpstreamsConfig.Labels.fromMap(it)),
ethereumTargets ethereumTargets
) )
} }

View File

@@ -16,49 +16,50 @@
package io.emeraldpay.dshackle.upstream package io.emeraldpay.dshackle.upstream
import io.emeraldpay.dshackle.config.UpstreamsConfig import io.emeraldpay.dshackle.config.UpstreamsConfig
import io.emeraldpay.dshackle.startup.QuorumForLabels
import org.codehaus.groovy.runtime.DefaultGroovyMethods import org.codehaus.groovy.runtime.DefaultGroovyMethods
import spock.lang.Specification import spock.lang.Specification
class NodeDetailsListSpec extends Specification { class QuorumForLabelsSpec extends Specification {
def "Adds new node"() { def "Adds new node"() {
setup: setup:
def list = new NodeDetailsList() def list = new QuorumForLabels()
when: when:
list.add(new NodeDetailsList.NodeDetails(1, asLabels([foo: "bar"]))) list.add(new QuorumForLabels.QuorumItem(1, asLabels([foo: "bar"])))
then: then:
list.nodes.size() == 1 list.all.size() == 1
with(list.nodes.get(0)) { with(list.all.get(0)) {
quorum == 1 quorum == 1
DefaultGroovyMethods.equals(labels, [foo: "bar"]) DefaultGroovyMethods.equals(labels, [foo: "bar"])
} }
when: when:
list.add(new NodeDetailsList.NodeDetails(2, asLabels([foo: "not-bar"]))) list.add(new QuorumForLabels.QuorumItem(2, asLabels([foo: "not-bar"])))
then: then:
list.nodes.size() == 2 list.all.size() == 2
with(list.nodes.get(0)) { with(list.all.get(0)) {
quorum == 1 quorum == 1
DefaultGroovyMethods.equals(labels, [foo: "bar"]) DefaultGroovyMethods.equals(labels, [foo: "bar"])
} }
with(list.nodes.get(1)) { with(list.all.get(1)) {
quorum == 2 quorum == 2
DefaultGroovyMethods.equals(labels, [foo: "not-bar"]) DefaultGroovyMethods.equals(labels, [foo: "not-bar"])
} }
when: when:
list.add(new NodeDetailsList.NodeDetails(1, asLabels([foo: "bar", baz: "baz"]))) list.add(new QuorumForLabels.QuorumItem(1, asLabels([foo: "bar", baz: "baz"])))
then: then:
list.nodes.size() == 3 list.all.size() == 3
with(list.nodes.get(0)) { with(list.all.get(0)) {
quorum == 1 quorum == 1
DefaultGroovyMethods.equals(labels, [foo: "bar"]) DefaultGroovyMethods.equals(labels, [foo: "bar"])
} }
with(list.nodes.get(1)) { with(list.all.get(1)) {
quorum == 2 quorum == 2
DefaultGroovyMethods.equals(labels, [foo: "not-bar"]) DefaultGroovyMethods.equals(labels, [foo: "not-bar"])
} }
with(list.nodes.get(2)) { with(list.all.get(2)) {
quorum == 1 quorum == 1
DefaultGroovyMethods.equals(labels, [foo: "bar", baz: "baz"]) DefaultGroovyMethods.equals(labels, [foo: "bar", baz: "baz"])
} }
@@ -66,19 +67,19 @@ class NodeDetailsListSpec extends Specification {
def "Updates existing node"() { def "Updates existing node"() {
setup: setup:
def list = new NodeDetailsList() def list = new QuorumForLabels()
list.add(new NodeDetailsList.NodeDetails(1, asLabels([foo: "bar"]))) list.add(new QuorumForLabels.QuorumItem(1, asLabels([foo: "bar"])))
list.add(new NodeDetailsList.NodeDetails(1, asLabels([baz: "true"]))) list.add(new QuorumForLabels.QuorumItem(1, asLabels([baz: "true"])))
when: when:
list.add(new NodeDetailsList.NodeDetails(2, asLabels([baz: "true"]))) list.add(new QuorumForLabels.QuorumItem(2, asLabels([baz: "true"])))
then: then:
list.nodes.size() == 2 list.all.size() == 2
with(list.nodes.get(0)) { with(list.all.get(0)) {
quorum == 1 quorum == 1
DefaultGroovyMethods.equals(labels, [foo: "bar"]) DefaultGroovyMethods.equals(labels, [foo: "bar"])
} }
with(list.nodes.get(1)) { with(list.all.get(1)) {
quorum == 3 quorum == 3
DefaultGroovyMethods.equals(labels, [baz: "true"]) DefaultGroovyMethods.equals(labels, [baz: "true"])
} }
@@ -86,23 +87,23 @@ class NodeDetailsListSpec extends Specification {
def "Applies all from another list"() { def "Applies all from another list"() {
setup: setup:
def list1 = new NodeDetailsList() def list1 = new QuorumForLabels()
list1.add(new NodeDetailsList.NodeDetails(1, asLabels([foo: "bar"]))) list1.add(new QuorumForLabels.QuorumItem(1, asLabels([foo: "bar"])))
list1.add(new NodeDetailsList.NodeDetails(2, asLabels([baz: "true"]))) list1.add(new QuorumForLabels.QuorumItem(2, asLabels([baz: "true"])))
list1.add(new NodeDetailsList.NodeDetails(3, asLabels([baz: "true", bar: "bar"]))) list1.add(new QuorumForLabels.QuorumItem(3, asLabels([baz: "true", bar: "bar"])))
def list2 = new NodeDetailsList() def list2 = new QuorumForLabels()
list1.add(new NodeDetailsList.NodeDetails(4, asLabels([foo: "bar"]))) list1.add(new QuorumForLabels.QuorumItem(4, asLabels([foo: "bar"])))
list1.add(new NodeDetailsList.NodeDetails(5, asLabels([baz: "true", bar: "bar"]))) list1.add(new QuorumForLabels.QuorumItem(5, asLabels([baz: "true", bar: "bar"])))
list1.add(new NodeDetailsList.NodeDetails(6, asLabels([bar: "bar"]))) list1.add(new QuorumForLabels.QuorumItem(6, asLabels([bar: "bar"])))
def list = new NodeDetailsList() def list = new QuorumForLabels()
when: when:
list.add(list1) list.add(list1)
list.add(list2) list.add(list2)
def nodes = list.nodes.toSorted { it.quorum } def nodes = list.all.toSorted { it.quorum }
then: then:
list.nodes.size() == 4 list.all.size() == 4
with(nodes.get(0)) { with(nodes.get(0)) {
quorum == 2 quorum == 2
DefaultGroovyMethods.equals(labels, [baz: "true"]) DefaultGroovyMethods.equals(labels, [baz: "true"])

View File

@@ -13,9 +13,12 @@
* 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 package io.emeraldpay.dshackle.upstream.calls
import io.emeraldpay.dshackle.quorum.AlwaysQuorum 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 import spock.lang.Specification
class AggregatedCallMethodsSpec extends Specification { class AggregatedCallMethodsSpec extends Specification {

View File

@@ -13,9 +13,11 @@
* 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 package io.emeraldpay.dshackle.upstream.calls
import io.emeraldpay.dshackle.quorum.AlwaysQuorum import io.emeraldpay.dshackle.quorum.AlwaysQuorum
import io.emeraldpay.dshackle.upstream.calls.DirectCallMethods
import io.emeraldpay.dshackle.upstream.calls.ManagedCallMethods
import spock.lang.Specification import spock.lang.Specification
class ManagedCallMethodsSpec extends Specification { class ManagedCallMethodsSpec extends Specification {

View File

@@ -16,7 +16,7 @@
package io.emeraldpay.dshackle.upstream.ethereum package io.emeraldpay.dshackle.upstream.ethereum
import io.emeraldpay.dshackle.test.TestingCommons 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.ReactorRpcClient
import io.infinitape.etherjar.rpc.RpcException import io.infinitape.etherjar.rpc.RpcException
import io.infinitape.etherjar.rpc.RpcResponseError import io.infinitape.etherjar.rpc.RpcResponseError

View File

@@ -22,22 +22,17 @@ import io.emeraldpay.api.proto.BlockchainOuterClass
import io.emeraldpay.api.proto.Common import io.emeraldpay.api.proto.Common
import io.emeraldpay.dshackle.test.MockServer import io.emeraldpay.dshackle.test.MockServer
import io.emeraldpay.dshackle.test.TestingCommons import io.emeraldpay.dshackle.test.TestingCommons
import io.emeraldpay.dshackle.upstream.QuorumBasedMethods
import io.emeraldpay.dshackle.upstream.UpstreamAvailability import io.emeraldpay.dshackle.upstream.UpstreamAvailability
import io.emeraldpay.dshackle.upstream.grpc.GrpcUpstream
import io.emeraldpay.grpc.Chain import io.emeraldpay.grpc.Chain
import io.grpc.stub.StreamObserver import io.grpc.stub.StreamObserver
import io.infinitape.etherjar.domain.BlockHash import io.infinitape.etherjar.domain.BlockHash
import io.infinitape.etherjar.rpc.JacksonRpcConverter
import io.infinitape.etherjar.rpc.ReactorRpcClient import io.infinitape.etherjar.rpc.ReactorRpcClient
import io.infinitape.etherjar.rpc.emerald.ReactorEmeraldClient import io.infinitape.etherjar.rpc.emerald.ReactorEmeraldClient
import io.infinitape.etherjar.rpc.json.BlockJson import io.infinitape.etherjar.rpc.json.BlockJson
import reactor.test.StepVerifier
import spock.lang.Specification import spock.lang.Specification
import java.time.Duration import java.time.Duration
import java.util.concurrent.CompletableFuture import java.util.concurrent.CompletableFuture
import java.util.concurrent.Executors
class GrpcUpstreamSpec extends Specification { class GrpcUpstreamSpec extends Specification {