diff --git a/src/main/kotlin/io/emeraldpay/dshackle/rpc/Describe.kt b/src/main/kotlin/io/emeraldpay/dshackle/rpc/Describe.kt index 1ed42c66..2ca6cb44 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/rpc/Describe.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/rpc/Describe.kt @@ -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 -> diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/ConfiguredUpstreams.kt b/src/main/kotlin/io/emeraldpay/dshackle/startup/ConfiguredUpstreams.kt similarity index 97% rename from src/main/kotlin/io/emeraldpay/dshackle/upstream/ConfiguredUpstreams.kt rename to src/main/kotlin/io/emeraldpay/dshackle/startup/ConfiguredUpstreams.kt index e0f2fa0f..07602756 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/ConfiguredUpstreams.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/startup/ConfiguredUpstreams.kt @@ -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)) diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/NodeDetailsList.kt b/src/main/kotlin/io/emeraldpay/dshackle/startup/QuorumForLabels.kt similarity index 70% rename from src/main/kotlin/io/emeraldpay/dshackle/upstream/NodeDetailsList.kt rename to src/main/kotlin/io/emeraldpay/dshackle/startup/QuorumForLabels.kt index 033c0d10..6ea64602 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/NodeDetailsList.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/startup/QuorumForLabels.kt @@ -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() + private val nodes = ArrayList() - 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 { + fun getAll(): List { 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 { } } diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/UpstreamChange.kt b/src/main/kotlin/io/emeraldpay/dshackle/startup/UpstreamChange.kt similarity index 92% rename from src/main/kotlin/io/emeraldpay/dshackle/upstream/UpstreamChange.kt rename to src/main/kotlin/io/emeraldpay/dshackle/startup/UpstreamChange.kt index 81e36b77..d57061d7 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/UpstreamChange.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/startup/UpstreamChange.kt @@ -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( diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/AggregatedUpstream.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/AggregatedUpstream.kt index 81ed0164..199f8fa1 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/AggregatedUpstream.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/AggregatedUpstream.kt @@ -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 diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/CurrentUpstreams.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/CurrentUpstreams.kt index 345bad54..b9232f58 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/CurrentUpstreams.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/CurrentUpstreams.kt @@ -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 diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/Upstream.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/Upstream.kt index 8102494d..f42c0002 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/Upstream.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/Upstream.kt @@ -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 diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/Upstreams.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/Upstreams.kt index c823b0e2..f9e89874 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/Upstreams.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/Upstreams.kt @@ -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 diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/AggregatedCallMethods.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/calls/AggregatedCallMethods.kt similarity index 73% rename from src/main/kotlin/io/emeraldpay/dshackle/upstream/AggregatedCallMethods.kt rename to src/main/kotlin/io/emeraldpay/dshackle/upstream/calls/AggregatedCallMethods.kt index e2967f06..1a3ee229 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/AggregatedCallMethods.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/calls/AggregatedCallMethods.kt @@ -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 { @@ -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 { 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) diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/CallMethods.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/calls/CallMethods.kt similarity index 62% rename from src/main/kotlin/io/emeraldpay/dshackle/upstream/CallMethods.kt rename to src/main/kotlin/io/emeraldpay/dshackle/upstream/calls/CallMethods.kt index 4765f893..f67b112e 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/CallMethods.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/calls/CallMethods.kt @@ -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 + + /** + * @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 } \ No newline at end of file diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/DirectCallMethods.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/calls/DirectCallMethods.kt similarity index 87% rename from src/main/kotlin/io/emeraldpay/dshackle/upstream/DirectCallMethods.kt rename to src/main/kotlin/io/emeraldpay/dshackle/upstream/calls/DirectCallMethods.kt index f07e65b8..eea7d106 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/DirectCallMethods.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/calls/DirectCallMethods.kt @@ -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) : CallMethods { constructor(): this(emptySet()) diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/ManagedCallMethods.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/calls/ManagedCallMethods.kt similarity index 84% rename from src/main/kotlin/io/emeraldpay/dshackle/upstream/ManagedCallMethods.kt rename to src/main/kotlin/io/emeraldpay/dshackle/upstream/calls/ManagedCallMethods.kt index 0ac1c3a0..5eee6839 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/ManagedCallMethods.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/calls/ManagedCallMethods.kt @@ -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, diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/QuorumBasedMethods.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/calls/QuorumBasedMethods.kt similarity index 94% rename from src/main/kotlin/io/emeraldpay/dshackle/upstream/QuorumBasedMethods.kt rename to src/main/kotlin/io/emeraldpay/dshackle/upstream/calls/QuorumBasedMethods.kt index 44197d79..17146ed3 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/QuorumBasedMethods.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/calls/QuorumBasedMethods.kt @@ -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 diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/ethereum/DirectEthereumApi.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/ethereum/DirectEthereumApi.kt index a0a48719..11b2d9eb 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/ethereum/DirectEthereumApi.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/ethereum/DirectEthereumApi.kt @@ -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 diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/ethereum/EthereumUpstream.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/ethereum/EthereumUpstream.kt index bcfadbac..7546b3d9 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/ethereum/EthereumUpstream.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/ethereum/EthereumUpstream.kt @@ -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()) diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/grpc/GrpcUpstream.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/grpc/GrpcUpstream.kt index e7e4f496..6f19cef8 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/grpc/GrpcUpstream.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/grpc/GrpcUpstream.kt @@ -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()) + private val nodes = AtomicReference(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() 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 } } diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/grpc/GrpcUpstreams.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/grpc/GrpcUpstreams.kt index 694dbc0c..89be5917 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/grpc/GrpcUpstreams.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/grpc/GrpcUpstreams.kt @@ -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 diff --git a/src/test/groovy/io/emeraldpay/dshackle/test/EthereumApiMock.groovy b/src/test/groovy/io/emeraldpay/dshackle/test/EthereumApiMock.groovy index f5f62883..18e8a9d3 100644 --- a/src/test/groovy/io/emeraldpay/dshackle/test/EthereumApiMock.groovy +++ b/src/test/groovy/io/emeraldpay/dshackle/test/EthereumApiMock.groovy @@ -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 diff --git a/src/test/groovy/io/emeraldpay/dshackle/test/EthereumApiStub.groovy b/src/test/groovy/io/emeraldpay/dshackle/test/EthereumApiStub.groovy index 7926abf5..c225508e 100644 --- a/src/test/groovy/io/emeraldpay/dshackle/test/EthereumApiStub.groovy +++ b/src/test/groovy/io/emeraldpay/dshackle/test/EthereumApiStub.groovy @@ -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 diff --git a/src/test/groovy/io/emeraldpay/dshackle/test/EthereumUpstreamMock.groovy b/src/test/groovy/io/emeraldpay/dshackle/test/EthereumUpstreamMock.groovy index bb438605..42828cf7 100644 --- a/src/test/groovy/io/emeraldpay/dshackle/test/EthereumUpstreamMock.groovy +++ b/src/test/groovy/io/emeraldpay/dshackle/test/EthereumUpstreamMock.groovy @@ -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) diff --git a/src/test/groovy/io/emeraldpay/dshackle/test/TestingCommons.groovy b/src/test/groovy/io/emeraldpay/dshackle/test/TestingCommons.groovy index ce3f0ff7..918d01f6 100644 --- a/src/test/groovy/io/emeraldpay/dshackle/test/TestingCommons.groovy +++ b/src/test/groovy/io/emeraldpay/dshackle/test/TestingCommons.groovy @@ -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 diff --git a/src/test/groovy/io/emeraldpay/dshackle/test/UpstreamsMock.groovy b/src/test/groovy/io/emeraldpay/dshackle/test/UpstreamsMock.groovy index f86d4ecd..137fada7 100644 --- a/src/test/groovy/io/emeraldpay/dshackle/test/UpstreamsMock.groovy +++ b/src/test/groovy/io/emeraldpay/dshackle/test/UpstreamsMock.groovy @@ -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 diff --git a/src/test/groovy/io/emeraldpay/dshackle/upstream/AggregatedUpstreamSpec.groovy b/src/test/groovy/io/emeraldpay/dshackle/upstream/AggregatedUpstreamSpec.groovy index f8b517f8..15a9e23a 100644 --- a/src/test/groovy/io/emeraldpay/dshackle/upstream/AggregatedUpstreamSpec.groovy +++ b/src/test/groovy/io/emeraldpay/dshackle/upstream/AggregatedUpstreamSpec.groovy @@ -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 diff --git a/src/test/groovy/io/emeraldpay/dshackle/upstream/CurrentUpstreamsSpec.groovy b/src/test/groovy/io/emeraldpay/dshackle/upstream/CurrentUpstreamsSpec.groovy index 56f6ea0e..d5e09d4b 100644 --- a/src/test/groovy/io/emeraldpay/dshackle/upstream/CurrentUpstreamsSpec.groovy +++ b/src/test/groovy/io/emeraldpay/dshackle/upstream/CurrentUpstreamsSpec.groovy @@ -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 diff --git a/src/test/groovy/io/emeraldpay/dshackle/upstream/FilteredApisSpec.groovy b/src/test/groovy/io/emeraldpay/dshackle/upstream/FilteredApisSpec.groovy index a3ff2298..24bb43fb 100644 --- a/src/test/groovy/io/emeraldpay/dshackle/upstream/FilteredApisSpec.groovy +++ b/src/test/groovy/io/emeraldpay/dshackle/upstream/FilteredApisSpec.groovy @@ -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 ) } diff --git a/src/test/groovy/io/emeraldpay/dshackle/upstream/NodeDetailsListSpec.groovy b/src/test/groovy/io/emeraldpay/dshackle/upstream/QuorumForLabelsSpec.groovy similarity index 62% rename from src/test/groovy/io/emeraldpay/dshackle/upstream/NodeDetailsListSpec.groovy rename to src/test/groovy/io/emeraldpay/dshackle/upstream/QuorumForLabelsSpec.groovy index 89c48dfe..3b370651 100644 --- a/src/test/groovy/io/emeraldpay/dshackle/upstream/NodeDetailsListSpec.groovy +++ b/src/test/groovy/io/emeraldpay/dshackle/upstream/QuorumForLabelsSpec.groovy @@ -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"]) diff --git a/src/test/groovy/io/emeraldpay/dshackle/upstream/AggregatedCallMethodsSpec.groovy b/src/test/groovy/io/emeraldpay/dshackle/upstream/calls/AggregatedCallMethodsSpec.groovy similarity index 94% rename from src/test/groovy/io/emeraldpay/dshackle/upstream/AggregatedCallMethodsSpec.groovy rename to src/test/groovy/io/emeraldpay/dshackle/upstream/calls/AggregatedCallMethodsSpec.groovy index aad02fa2..2e02c06b 100644 --- a/src/test/groovy/io/emeraldpay/dshackle/upstream/AggregatedCallMethodsSpec.groovy +++ b/src/test/groovy/io/emeraldpay/dshackle/upstream/calls/AggregatedCallMethodsSpec.groovy @@ -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 { diff --git a/src/test/groovy/io/emeraldpay/dshackle/upstream/ManagedCallMethodsSpec.groovy b/src/test/groovy/io/emeraldpay/dshackle/upstream/calls/ManagedCallMethodsSpec.groovy similarity index 91% rename from src/test/groovy/io/emeraldpay/dshackle/upstream/ManagedCallMethodsSpec.groovy rename to src/test/groovy/io/emeraldpay/dshackle/upstream/calls/ManagedCallMethodsSpec.groovy index 0f3b5301..b1146cef 100644 --- a/src/test/groovy/io/emeraldpay/dshackle/upstream/ManagedCallMethodsSpec.groovy +++ b/src/test/groovy/io/emeraldpay/dshackle/upstream/calls/ManagedCallMethodsSpec.groovy @@ -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 { diff --git a/src/test/groovy/io/emeraldpay/dshackle/upstream/ethereum/DirectEthereumApiSpec.groovy b/src/test/groovy/io/emeraldpay/dshackle/upstream/ethereum/DirectEthereumApiSpec.groovy index 988af747..ae51e7ed 100644 --- a/src/test/groovy/io/emeraldpay/dshackle/upstream/ethereum/DirectEthereumApiSpec.groovy +++ b/src/test/groovy/io/emeraldpay/dshackle/upstream/ethereum/DirectEthereumApiSpec.groovy @@ -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 diff --git a/src/test/groovy/io/emeraldpay/dshackle/upstream/grpc/GrpcUpstreamSpec.groovy b/src/test/groovy/io/emeraldpay/dshackle/upstream/grpc/GrpcUpstreamSpec.groovy index 05c39dde..b2a38ef6 100644 --- a/src/test/groovy/io/emeraldpay/dshackle/upstream/grpc/GrpcUpstreamSpec.groovy +++ b/src/test/groovy/io/emeraldpay/dshackle/upstream/grpc/GrpcUpstreamSpec.groovy @@ -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 {