custom ws subscriptions for vara (#334)
This commit is contained in:
@@ -18,7 +18,6 @@ package io.emeraldpay.dshackle.rpc
|
|||||||
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.api.proto.BlockchainOuterClass.NativeSubscribeReplyItem
|
import io.emeraldpay.api.proto.BlockchainOuterClass.NativeSubscribeReplyItem
|
||||||
import io.emeraldpay.dshackle.BlockchainType
|
|
||||||
import io.emeraldpay.dshackle.Chain
|
import io.emeraldpay.dshackle.Chain
|
||||||
import io.emeraldpay.dshackle.Global
|
import io.emeraldpay.dshackle.Global
|
||||||
import io.emeraldpay.dshackle.SilentException
|
import io.emeraldpay.dshackle.SilentException
|
||||||
@@ -57,8 +56,11 @@ open class NativeSubscribe(
|
|||||||
|
|
||||||
fun start(request: BlockchainOuterClass.NativeSubscribeRequest): Publisher<ResponseHolder> {
|
fun start(request: BlockchainOuterClass.NativeSubscribeRequest): Publisher<ResponseHolder> {
|
||||||
val chain = Chain.byId(request.chainValue)
|
val chain = Chain.byId(request.chainValue)
|
||||||
if (chain.type != BlockchainType.ETHEREUM) {
|
|
||||||
return Mono.error(UnsupportedOperationException("Native subscribe is not supported for ${chain.chainCode}"))
|
val multistream = getUpstream(chain)
|
||||||
|
|
||||||
|
if (!multistream.getSubscriptionTopics().contains(request.method)) {
|
||||||
|
return Mono.error(UnsupportedOperationException("subscribe ${request.method} is not supported for ${chain.chainCode}"))
|
||||||
}
|
}
|
||||||
|
|
||||||
val nonce = request.nonce.takeIf { it != 0L }
|
val nonce = request.nonce.takeIf { it != 0L }
|
||||||
@@ -69,7 +71,7 @@ open class NativeSubscribe(
|
|||||||
* If not possible - performs subscription logic on the current instance
|
* If not possible - performs subscription logic on the current instance
|
||||||
* @see EthereumLikeMultistream.tryProxySubscribe
|
* @see EthereumLikeMultistream.tryProxySubscribe
|
||||||
*/
|
*/
|
||||||
val publisher = getUpstream(chain).tryProxySubscribe(matcher, request) ?: run {
|
val publisher = multistream.tryProxySubscribe(matcher, request) ?: run {
|
||||||
val method = request.method
|
val method = request.method
|
||||||
val params: Any? = request.payload?.takeIf { !it.isEmpty }?.let {
|
val params: Any? = request.payload?.takeIf { !it.isEmpty }?.let {
|
||||||
objectMapper.readValue(it.newInput(), Map::class.java)
|
objectMapper.readValue(it.newInput(), Map::class.java)
|
||||||
@@ -110,7 +112,13 @@ open class NativeSubscribe(
|
|||||||
if (holder.response is NativeSubscribeReplyItem) {
|
if (holder.response is NativeSubscribeReplyItem) {
|
||||||
return holder.response
|
return holder.response
|
||||||
}
|
}
|
||||||
val result = objectMapper.writeValueAsBytes(holder.response)
|
|
||||||
|
val result = if (holder.response is ByteArray) {
|
||||||
|
holder.response
|
||||||
|
} else {
|
||||||
|
objectMapper.writeValueAsBytes(holder.response)
|
||||||
|
}
|
||||||
|
|
||||||
val builder = NativeSubscribeReplyItem.newBuilder()
|
val builder = NativeSubscribeReplyItem.newBuilder()
|
||||||
.setPayload(ByteString.copyFrom(result))
|
.setPayload(ByteString.copyFrom(result))
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2022 EmeraldPay, Inc
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package io.emeraldpay.dshackle.upstream
|
|
||||||
|
|
||||||
interface HasEgressSubscription {
|
|
||||||
fun getEgressSubscription(): EgressSubscription
|
|
||||||
}
|
|
||||||
@@ -52,7 +52,7 @@ import kotlin.concurrent.withLock
|
|||||||
abstract class Multistream(
|
abstract class Multistream(
|
||||||
val chain: Chain,
|
val chain: Chain,
|
||||||
val caches: Caches,
|
val caches: Caches,
|
||||||
) : Upstream, Lifecycle, HasEgressSubscription {
|
) : Upstream, Lifecycle {
|
||||||
|
|
||||||
abstract fun getUpstreams(): MutableList<out Upstream>
|
abstract fun getUpstreams(): MutableList<out Upstream>
|
||||||
abstract fun addUpstreamInternal(u: Upstream)
|
abstract fun addUpstreamInternal(u: Upstream)
|
||||||
@@ -498,4 +498,6 @@ abstract class Multistream(
|
|||||||
return map.values.min()
|
return map.values.min()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract fun getEgressSubscription(): EgressSubscription
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,17 @@ import io.emeraldpay.etherjar.rpc.RpcException
|
|||||||
*/
|
*/
|
||||||
class DefaultPolkadotMethods : CallMethods {
|
class DefaultPolkadotMethods : CallMethods {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val subs = setOf(
|
||||||
|
Pair("subscribe_newHead", "unsubscribe_newHead"),
|
||||||
|
Pair("chain_subscribeAllHeads", "chain_unsubscribeAllHeads"),
|
||||||
|
Pair("chain_subscribeFinalizedHeads", "chain_unsubscribeFinalizedHeads"),
|
||||||
|
Pair("chain_subscribeNewHeads", "chain_unsubscribeNewHeads"),
|
||||||
|
Pair("chain_subscribeRuntimeVersion", "chain_unsubscribeNewHeads"),
|
||||||
|
Pair("chain_subscribeRuntimeVersion", "chain_unsubscribeRuntimeVersion"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private val all = setOf(
|
private val all = setOf(
|
||||||
"author_pendingExtrinsics",
|
"author_pendingExtrinsics",
|
||||||
"author_removeExtrinsic",
|
"author_removeExtrinsic",
|
||||||
@@ -37,16 +48,6 @@ class DefaultPolkadotMethods : CallMethods {
|
|||||||
"chain_getHead",
|
"chain_getHead",
|
||||||
"chain_getHeader",
|
"chain_getHeader",
|
||||||
"chain_getRuntimeVersion",
|
"chain_getRuntimeVersion",
|
||||||
"chain_subscribeAllHeads",
|
|
||||||
"chain_subscribeFinalizedHeads",
|
|
||||||
"chain_subscribeNewHeads",
|
|
||||||
"chain_subscribeRuntimeVersion",
|
|
||||||
"chain_unsubscribeAllHeads",
|
|
||||||
"chain_unsubscribeFinalisedHeads",
|
|
||||||
"chain_unsubscribeFinalizedHeads",
|
|
||||||
"chain_unsubscribeNewHead",
|
|
||||||
"chain_unsubscribeNewHeads",
|
|
||||||
"chain_unsubscribeRuntimeVersion",
|
|
||||||
"childstate_getKeys",
|
"childstate_getKeys",
|
||||||
"childstate_getKeysPaged",
|
"childstate_getKeysPaged",
|
||||||
"childstate_getKeysPagedAt",
|
"childstate_getKeysPagedAt",
|
||||||
@@ -87,9 +88,7 @@ class DefaultPolkadotMethods : CallMethods {
|
|||||||
"state_queryStorageAt",
|
"state_queryStorageAt",
|
||||||
"state_traceBlock",
|
"state_traceBlock",
|
||||||
"state_trieMigrationStatus",
|
"state_trieMigrationStatus",
|
||||||
"subscribe_newHead",
|
|
||||||
"system_chain",
|
"system_chain",
|
||||||
"unsubscribe_newHead",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
private val add = setOf(
|
private val add = setOf(
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import io.emeraldpay.dshackle.upstream.CachingReader
|
|||||||
import io.emeraldpay.dshackle.upstream.Capability
|
import io.emeraldpay.dshackle.upstream.Capability
|
||||||
import io.emeraldpay.dshackle.upstream.EgressSubscription
|
import io.emeraldpay.dshackle.upstream.EgressSubscription
|
||||||
import io.emeraldpay.dshackle.upstream.Head
|
import io.emeraldpay.dshackle.upstream.Head
|
||||||
|
import io.emeraldpay.dshackle.upstream.IngressSubscription
|
||||||
import io.emeraldpay.dshackle.upstream.LabelsDetector
|
import io.emeraldpay.dshackle.upstream.LabelsDetector
|
||||||
import io.emeraldpay.dshackle.upstream.Multistream
|
import io.emeraldpay.dshackle.upstream.Multistream
|
||||||
import io.emeraldpay.dshackle.upstream.Upstream
|
import io.emeraldpay.dshackle.upstream.Upstream
|
||||||
@@ -16,6 +17,7 @@ import io.emeraldpay.dshackle.upstream.UpstreamValidator
|
|||||||
import io.emeraldpay.dshackle.upstream.calls.CallMethods
|
import io.emeraldpay.dshackle.upstream.calls.CallMethods
|
||||||
import io.emeraldpay.dshackle.upstream.ethereum.subscribe.AggregatedPendingTxes
|
import io.emeraldpay.dshackle.upstream.ethereum.subscribe.AggregatedPendingTxes
|
||||||
import io.emeraldpay.dshackle.upstream.ethereum.subscribe.EthereumLabelsDetector
|
import io.emeraldpay.dshackle.upstream.ethereum.subscribe.EthereumLabelsDetector
|
||||||
|
import io.emeraldpay.dshackle.upstream.ethereum.subscribe.EthereumWsIngressSubscription
|
||||||
import io.emeraldpay.dshackle.upstream.ethereum.subscribe.NoPendingTxes
|
import io.emeraldpay.dshackle.upstream.ethereum.subscribe.NoPendingTxes
|
||||||
import io.emeraldpay.dshackle.upstream.ethereum.subscribe.PendingTxesSource
|
import io.emeraldpay.dshackle.upstream.ethereum.subscribe.PendingTxesSource
|
||||||
import io.emeraldpay.dshackle.upstream.generic.CachingReaderBuilder
|
import io.emeraldpay.dshackle.upstream.generic.CachingReaderBuilder
|
||||||
@@ -91,4 +93,8 @@ object EthereumChainSpecific : ChainSpecific {
|
|||||||
}
|
}
|
||||||
return upstream.getIngressSubscription().getAvailableTopics().plus(subs).toSet().toList()
|
return upstream.getIngressSubscription().getAvailableTopics().plus(subs).toSet().toList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun makeIngressSubscription(ws: WsSubscriptions): IngressSubscription {
|
||||||
|
return EthereumWsIngressSubscription(ws)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ package io.emeraldpay.dshackle.upstream.ethereum.subscribe
|
|||||||
import com.github.benmanes.caffeine.cache.Caffeine
|
import com.github.benmanes.caffeine.cache.Caffeine
|
||||||
import io.emeraldpay.dshackle.upstream.Selector
|
import io.emeraldpay.dshackle.upstream.Selector
|
||||||
import io.emeraldpay.etherjar.domain.TransactionId
|
import io.emeraldpay.etherjar.domain.TransactionId
|
||||||
import org.slf4j.LoggerFactory
|
|
||||||
import reactor.core.publisher.Flux
|
import reactor.core.publisher.Flux
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
|
|
||||||
@@ -26,10 +25,6 @@ class AggregatedPendingTxes(
|
|||||||
private val sources: List<PendingTxesSource>,
|
private val sources: List<PendingTxesSource>,
|
||||||
) : PendingTxesSource {
|
) : PendingTxesSource {
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val log = LoggerFactory.getLogger(AggregatedPendingTxes::class.java)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val track = Caffeine.newBuilder()
|
private val track = Caffeine.newBuilder()
|
||||||
.expireAfterWrite(Duration.ofSeconds(30))
|
.expireAfterWrite(Duration.ofSeconds(30))
|
||||||
.maximumSize(10_000)
|
.maximumSize(10_000)
|
||||||
|
|||||||
@@ -14,12 +14,14 @@ import io.emeraldpay.dshackle.reader.JsonRpcReader
|
|||||||
import io.emeraldpay.dshackle.upstream.CachingReader
|
import io.emeraldpay.dshackle.upstream.CachingReader
|
||||||
import io.emeraldpay.dshackle.upstream.EgressSubscription
|
import io.emeraldpay.dshackle.upstream.EgressSubscription
|
||||||
import io.emeraldpay.dshackle.upstream.Head
|
import io.emeraldpay.dshackle.upstream.Head
|
||||||
|
import io.emeraldpay.dshackle.upstream.IngressSubscription
|
||||||
import io.emeraldpay.dshackle.upstream.LabelsDetector
|
import io.emeraldpay.dshackle.upstream.LabelsDetector
|
||||||
import io.emeraldpay.dshackle.upstream.Multistream
|
import io.emeraldpay.dshackle.upstream.Multistream
|
||||||
import io.emeraldpay.dshackle.upstream.Upstream
|
import io.emeraldpay.dshackle.upstream.Upstream
|
||||||
import io.emeraldpay.dshackle.upstream.UpstreamValidator
|
import io.emeraldpay.dshackle.upstream.UpstreamValidator
|
||||||
import io.emeraldpay.dshackle.upstream.calls.CallMethods
|
import io.emeraldpay.dshackle.upstream.calls.CallMethods
|
||||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumChainSpecific
|
import io.emeraldpay.dshackle.upstream.ethereum.EthereumChainSpecific
|
||||||
|
import io.emeraldpay.dshackle.upstream.ethereum.WsSubscriptions
|
||||||
import io.emeraldpay.dshackle.upstream.polkadot.PolkadotChainSpecific
|
import io.emeraldpay.dshackle.upstream.polkadot.PolkadotChainSpecific
|
||||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
||||||
import io.emeraldpay.dshackle.upstream.starknet.StarknetChainSpecific
|
import io.emeraldpay.dshackle.upstream.starknet.StarknetChainSpecific
|
||||||
@@ -52,6 +54,8 @@ interface ChainSpecific {
|
|||||||
fun labelDetector(chain: Chain, reader: JsonRpcReader): LabelsDetector?
|
fun labelDetector(chain: Chain, reader: JsonRpcReader): LabelsDetector?
|
||||||
|
|
||||||
fun subscriptionTopics(upstream: GenericUpstream): List<String>
|
fun subscriptionTopics(upstream: GenericUpstream): List<String>
|
||||||
|
|
||||||
|
fun makeIngressSubscription(ws: WsSubscriptions): IngressSubscription
|
||||||
}
|
}
|
||||||
|
|
||||||
object ChainSpecificRegistry {
|
object ChainSpecificRegistry {
|
||||||
|
|||||||
@@ -5,13 +5,11 @@ import io.emeraldpay.dshackle.upstream.BlockValidator
|
|||||||
import io.emeraldpay.dshackle.upstream.DefaultUpstream
|
import io.emeraldpay.dshackle.upstream.DefaultUpstream
|
||||||
import io.emeraldpay.dshackle.upstream.Head
|
import io.emeraldpay.dshackle.upstream.Head
|
||||||
import io.emeraldpay.dshackle.upstream.IngressSubscription
|
import io.emeraldpay.dshackle.upstream.IngressSubscription
|
||||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumIngressSubscription
|
|
||||||
import io.emeraldpay.dshackle.upstream.ethereum.GenericWsHead
|
import io.emeraldpay.dshackle.upstream.ethereum.GenericWsHead
|
||||||
import io.emeraldpay.dshackle.upstream.ethereum.HeadLivenessValidator
|
import io.emeraldpay.dshackle.upstream.ethereum.HeadLivenessValidator
|
||||||
import io.emeraldpay.dshackle.upstream.ethereum.WsConnectionPool
|
import io.emeraldpay.dshackle.upstream.ethereum.WsConnectionPool
|
||||||
import io.emeraldpay.dshackle.upstream.ethereum.WsConnectionPoolFactory
|
import io.emeraldpay.dshackle.upstream.ethereum.WsConnectionPoolFactory
|
||||||
import io.emeraldpay.dshackle.upstream.ethereum.WsSubscriptionsImpl
|
import io.emeraldpay.dshackle.upstream.ethereum.WsSubscriptionsImpl
|
||||||
import io.emeraldpay.dshackle.upstream.ethereum.subscribe.EthereumWsIngressSubscription
|
|
||||||
import io.emeraldpay.dshackle.upstream.forkchoice.ForkChoice
|
import io.emeraldpay.dshackle.upstream.forkchoice.ForkChoice
|
||||||
import io.emeraldpay.dshackle.upstream.generic.ChainSpecific
|
import io.emeraldpay.dshackle.upstream.generic.ChainSpecific
|
||||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcWsClient
|
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcWsClient
|
||||||
@@ -32,7 +30,7 @@ class GenericWsConnector(
|
|||||||
private val pool: WsConnectionPool
|
private val pool: WsConnectionPool
|
||||||
private val reader: JsonRpcReader
|
private val reader: JsonRpcReader
|
||||||
private val head: GenericWsHead
|
private val head: GenericWsHead
|
||||||
private val subscriptions: EthereumIngressSubscription
|
private val subscriptions: IngressSubscription
|
||||||
private val liveness: HeadLivenessValidator
|
private val liveness: HeadLivenessValidator
|
||||||
init {
|
init {
|
||||||
pool = wsFactory.create(upstream)
|
pool = wsFactory.create(upstream)
|
||||||
@@ -49,7 +47,7 @@ class GenericWsConnector(
|
|||||||
chainSpecific,
|
chainSpecific,
|
||||||
)
|
)
|
||||||
liveness = HeadLivenessValidator(head, expectedBlockTime, headScheduler, upstream.getId())
|
liveness = HeadLivenessValidator(head, expectedBlockTime, headScheduler, upstream.getId())
|
||||||
subscriptions = EthereumWsIngressSubscription(wsSubscriptions)
|
subscriptions = chainSpecific.makeIngressSubscription(wsSubscriptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hasLiveSubscriptionHead(): Flux<Boolean> {
|
override fun hasLiveSubscriptionHead(): Flux<Boolean> {
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2022 EmeraldPay, Inc
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package io.emeraldpay.dshackle.upstream.generic.subscribe
|
||||||
|
|
||||||
|
import io.emeraldpay.dshackle.commons.DurableFlux
|
||||||
|
import io.emeraldpay.dshackle.commons.SharedFluxHolder
|
||||||
|
import io.emeraldpay.dshackle.upstream.Selector
|
||||||
|
import io.emeraldpay.dshackle.upstream.SubscriptionConnect
|
||||||
|
import reactor.core.publisher.Flux
|
||||||
|
import java.time.Duration
|
||||||
|
|
||||||
|
abstract class GenericPersistentConnect : SubscriptionConnect<Any> {
|
||||||
|
|
||||||
|
private val connectionSource = DurableFlux
|
||||||
|
.newBuilder()
|
||||||
|
.using(::createConnection)
|
||||||
|
.backoffOnError(Duration.ofMillis(100), 1.5, Duration.ofSeconds(60))
|
||||||
|
.build()
|
||||||
|
private val holder = SharedFluxHolder(
|
||||||
|
connectionSource::connect,
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun connect(matcher: Selector.Matcher): Flux<Any> {
|
||||||
|
return holder.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract fun createConnection(): Flux<Any>
|
||||||
|
}
|
||||||
@@ -11,14 +11,15 @@ import io.emeraldpay.dshackle.foundation.ChainOptions.Options
|
|||||||
import io.emeraldpay.dshackle.reader.JsonRpcReader
|
import io.emeraldpay.dshackle.reader.JsonRpcReader
|
||||||
import io.emeraldpay.dshackle.upstream.CachingReader
|
import io.emeraldpay.dshackle.upstream.CachingReader
|
||||||
import io.emeraldpay.dshackle.upstream.EgressSubscription
|
import io.emeraldpay.dshackle.upstream.EgressSubscription
|
||||||
import io.emeraldpay.dshackle.upstream.EmptyEgressSubscription
|
|
||||||
import io.emeraldpay.dshackle.upstream.Head
|
import io.emeraldpay.dshackle.upstream.Head
|
||||||
|
import io.emeraldpay.dshackle.upstream.IngressSubscription
|
||||||
import io.emeraldpay.dshackle.upstream.LabelsDetector
|
import io.emeraldpay.dshackle.upstream.LabelsDetector
|
||||||
import io.emeraldpay.dshackle.upstream.Multistream
|
import io.emeraldpay.dshackle.upstream.Multistream
|
||||||
import io.emeraldpay.dshackle.upstream.NoopCachingReader
|
import io.emeraldpay.dshackle.upstream.NoopCachingReader
|
||||||
import io.emeraldpay.dshackle.upstream.Upstream
|
import io.emeraldpay.dshackle.upstream.Upstream
|
||||||
import io.emeraldpay.dshackle.upstream.UpstreamValidator
|
import io.emeraldpay.dshackle.upstream.UpstreamValidator
|
||||||
import io.emeraldpay.dshackle.upstream.calls.CallMethods
|
import io.emeraldpay.dshackle.upstream.calls.CallMethods
|
||||||
|
import io.emeraldpay.dshackle.upstream.ethereum.WsSubscriptions
|
||||||
import io.emeraldpay.dshackle.upstream.generic.CachingReaderBuilder
|
import io.emeraldpay.dshackle.upstream.generic.CachingReaderBuilder
|
||||||
import io.emeraldpay.dshackle.upstream.generic.ChainSpecific
|
import io.emeraldpay.dshackle.upstream.generic.ChainSpecific
|
||||||
import io.emeraldpay.dshackle.upstream.generic.GenericUpstream
|
import io.emeraldpay.dshackle.upstream.generic.GenericUpstream
|
||||||
@@ -73,7 +74,7 @@ object PolkadotChainSpecific : ChainSpecific {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun subscriptionBuilder(headScheduler: Scheduler): (Multistream) -> EgressSubscription {
|
override fun subscriptionBuilder(headScheduler: Scheduler): (Multistream) -> EgressSubscription {
|
||||||
return { _ -> EmptyEgressSubscription }
|
return { ms -> PolkadotEgressSubscription(ms, headScheduler) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun makeCachingReaderBuilder(tracer: Tracer): CachingReaderBuilder {
|
override fun makeCachingReaderBuilder(tracer: Tracer): CachingReaderBuilder {
|
||||||
@@ -96,6 +97,10 @@ object PolkadotChainSpecific : ChainSpecific {
|
|||||||
override fun subscriptionTopics(upstream: GenericUpstream): List<String> {
|
override fun subscriptionTopics(upstream: GenericUpstream): List<String> {
|
||||||
return emptyList()
|
return emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun makeIngressSubscription(ws: WsSubscriptions): IngressSubscription {
|
||||||
|
return PolkadotIngressSubscription(ws)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package io.emeraldpay.dshackle.upstream.polkadot
|
||||||
|
|
||||||
|
import io.emeraldpay.dshackle.upstream.EgressSubscription
|
||||||
|
import io.emeraldpay.dshackle.upstream.Multistream
|
||||||
|
import io.emeraldpay.dshackle.upstream.Selector.Matcher
|
||||||
|
import io.emeraldpay.dshackle.upstream.calls.DefaultPolkadotMethods
|
||||||
|
import io.emeraldpay.dshackle.upstream.generic.GenericUpstream
|
||||||
|
import reactor.core.publisher.Flux
|
||||||
|
import reactor.core.scheduler.Scheduler
|
||||||
|
|
||||||
|
class PolkadotEgressSubscription(
|
||||||
|
val upstream: Multistream,
|
||||||
|
val scheduler: Scheduler,
|
||||||
|
) : EgressSubscription {
|
||||||
|
override fun getAvailableTopics(): List<String> {
|
||||||
|
return DefaultPolkadotMethods.subs.map { it.first }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun subscribe(topic: String, params: Any?, matcher: Matcher): Flux<ByteArray> {
|
||||||
|
val up = upstream.getUpstreams().shuffled().first { matcher.matches(it) } as GenericUpstream
|
||||||
|
return up.getIngressSubscription().get<ByteArray>(topic)?.connect(matcher) ?: Flux.empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package io.emeraldpay.dshackle.upstream.polkadot
|
||||||
|
|
||||||
|
import io.emeraldpay.dshackle.upstream.IngressSubscription
|
||||||
|
import io.emeraldpay.dshackle.upstream.SubscriptionConnect
|
||||||
|
import io.emeraldpay.dshackle.upstream.ethereum.WsSubscriptions
|
||||||
|
import io.emeraldpay.dshackle.upstream.generic.subscribe.GenericPersistentConnect
|
||||||
|
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
||||||
|
import reactor.core.publisher.Flux
|
||||||
|
import reactor.core.publisher.Mono
|
||||||
|
import java.time.Duration
|
||||||
|
|
||||||
|
class PolkadotIngressSubscription(val conn: WsSubscriptions) : IngressSubscription {
|
||||||
|
override fun getAvailableTopics(): List<String> {
|
||||||
|
return emptyList() // not used now
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
override fun <T> get(topic: String): SubscriptionConnect<T> {
|
||||||
|
return PolkaConnect(conn, topic) as SubscriptionConnect<T>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PolkaConnect(
|
||||||
|
val conn: WsSubscriptions,
|
||||||
|
val topic: String,
|
||||||
|
) : GenericPersistentConnect() {
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
override fun createConnection(): Flux<Any> {
|
||||||
|
return conn.subscribe(JsonRpcRequest(topic, listOf()))
|
||||||
|
.data
|
||||||
|
.timeout(Duration.ofSeconds(60), Mono.empty())
|
||||||
|
.onErrorResume { Mono.empty() } as Flux<Any>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,12 +13,15 @@ import io.emeraldpay.dshackle.upstream.CachingReader
|
|||||||
import io.emeraldpay.dshackle.upstream.EgressSubscription
|
import io.emeraldpay.dshackle.upstream.EgressSubscription
|
||||||
import io.emeraldpay.dshackle.upstream.EmptyEgressSubscription
|
import io.emeraldpay.dshackle.upstream.EmptyEgressSubscription
|
||||||
import io.emeraldpay.dshackle.upstream.Head
|
import io.emeraldpay.dshackle.upstream.Head
|
||||||
|
import io.emeraldpay.dshackle.upstream.IngressSubscription
|
||||||
import io.emeraldpay.dshackle.upstream.LabelsDetector
|
import io.emeraldpay.dshackle.upstream.LabelsDetector
|
||||||
import io.emeraldpay.dshackle.upstream.Multistream
|
import io.emeraldpay.dshackle.upstream.Multistream
|
||||||
|
import io.emeraldpay.dshackle.upstream.NoIngressSubscription
|
||||||
import io.emeraldpay.dshackle.upstream.NoopCachingReader
|
import io.emeraldpay.dshackle.upstream.NoopCachingReader
|
||||||
import io.emeraldpay.dshackle.upstream.Upstream
|
import io.emeraldpay.dshackle.upstream.Upstream
|
||||||
import io.emeraldpay.dshackle.upstream.UpstreamValidator
|
import io.emeraldpay.dshackle.upstream.UpstreamValidator
|
||||||
import io.emeraldpay.dshackle.upstream.calls.CallMethods
|
import io.emeraldpay.dshackle.upstream.calls.CallMethods
|
||||||
|
import io.emeraldpay.dshackle.upstream.ethereum.WsSubscriptions
|
||||||
import io.emeraldpay.dshackle.upstream.generic.CachingReaderBuilder
|
import io.emeraldpay.dshackle.upstream.generic.CachingReaderBuilder
|
||||||
import io.emeraldpay.dshackle.upstream.generic.ChainSpecific
|
import io.emeraldpay.dshackle.upstream.generic.ChainSpecific
|
||||||
import io.emeraldpay.dshackle.upstream.generic.GenericUpstream
|
import io.emeraldpay.dshackle.upstream.generic.GenericUpstream
|
||||||
@@ -91,6 +94,10 @@ object StarknetChainSpecific : ChainSpecific {
|
|||||||
override fun subscriptionTopics(upstream: GenericUpstream): List<String> {
|
override fun subscriptionTopics(upstream: GenericUpstream): List<String> {
|
||||||
return emptyList()
|
return emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun makeIngressSubscription(ws: WsSubscriptions): IngressSubscription {
|
||||||
|
return NoIngressSubscription()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ class NativeSubscribeSpec extends Specification {
|
|||||||
def up = Mock(GenericMultistream) {
|
def up = Mock(GenericMultistream) {
|
||||||
1 * it.tryProxySubscribe(_ as Selector.AnyLabelMatcher, call) >> null
|
1 * it.tryProxySubscribe(_ as Selector.AnyLabelMatcher, call) >> null
|
||||||
1 * it.getEgressSubscription() >> subscribe
|
1 * it.getEgressSubscription() >> subscribe
|
||||||
|
1 * it.getSubscriptionTopics() >> ["newHeads"]
|
||||||
}
|
}
|
||||||
|
|
||||||
def nativeSubscribe = new NativeSubscribe(new MultistreamHolderMock(Chain.ETHEREUM__MAINNET, up), signer)
|
def nativeSubscribe = new NativeSubscribe(new MultistreamHolderMock(Chain.ETHEREUM__MAINNET, up), signer)
|
||||||
@@ -84,6 +85,7 @@ class NativeSubscribeSpec extends Specification {
|
|||||||
def up = Mock(GenericMultistream) {
|
def up = Mock(GenericMultistream) {
|
||||||
1 * it.tryProxySubscribe(_ as Selector.AnyLabelMatcher, call) >> null
|
1 * it.tryProxySubscribe(_ as Selector.AnyLabelMatcher, call) >> null
|
||||||
1 * it.getEgressSubscription() >> subscribe
|
1 * it.getEgressSubscription() >> subscribe
|
||||||
|
1 * it.getSubscriptionTopics() >> ["logs"]
|
||||||
}
|
}
|
||||||
|
|
||||||
def nativeSubscribe = new NativeSubscribe(new MultistreamHolderMock(Chain.ETHEREUM__MAINNET, up), signer)
|
def nativeSubscribe = new NativeSubscribe(new MultistreamHolderMock(Chain.ETHEREUM__MAINNET, up), signer)
|
||||||
@@ -107,6 +109,7 @@ class NativeSubscribeSpec extends Specification {
|
|||||||
def up = Mock(GenericMultistream) {
|
def up = Mock(GenericMultistream) {
|
||||||
1 * it.tryProxySubscribe(_ as Selector.AnyLabelMatcher, call) >> Flux.just("{}")
|
1 * it.tryProxySubscribe(_ as Selector.AnyLabelMatcher, call) >> Flux.just("{}")
|
||||||
0 * it.getEgressSubscription()
|
0 * it.getEgressSubscription()
|
||||||
|
1 * it.getSubscriptionTopics() >> ["newHeads"]
|
||||||
}
|
}
|
||||||
|
|
||||||
def nativeSubscribe = new NativeSubscribe(new MultistreamHolderMock(Chain.ETHEREUM__MAINNET, up), signer)
|
def nativeSubscribe = new NativeSubscribe(new MultistreamHolderMock(Chain.ETHEREUM__MAINNET, up), signer)
|
||||||
|
|||||||
Reference in New Issue
Block a user