Upstream configuration improvement: (#149)
- now we can specify connector mode for better fine tuning of connection
This commit is contained in:
@@ -190,6 +190,27 @@ Dshackle currently supports
|
|||||||
- `ws` websocket connection (supposed to be used in addition to `rpc` connection)
|
- `ws` websocket connection (supposed to be used in addition to `rpc` connection)
|
||||||
- `grpc` connects to another Dshackle instance
|
- `grpc` connects to another Dshackle instance
|
||||||
|
|
||||||
|
==== Connection mixture modes
|
||||||
|
In case of rpc and ws connection we can specify different modes of works together:
|
||||||
|
|
||||||
|
|===
|
||||||
|
|Type |Description
|
||||||
|
|
||||||
|
|WS_ONLY
|
||||||
|
|Default mode in case WS endpoint specified. In this mode WS connection is used for all requests and subscriptions.
|
||||||
|
|
||||||
|
|RPC_ONLY
|
||||||
|
|Default in case WS endpoint not specified. In this mode RPC connection is used for all requests, subscriptions doesn't work, head subscription works through scheduled RPC head request.
|
||||||
|
|
||||||
|
|RPC_REQUESTS_WITH_MIXED_HEAD
|
||||||
|
|All requests are sent through RPC connection, eth_subscribe is sent through WS connection, head subscription works through scheduled RPC head request mixed with WS subscription.
|
||||||
|
|
||||||
|
|RPC_REQUESTS_WITH_WS_HEAD
|
||||||
|
|All requests are sent through RPC connection, all subscriptions works through WS connection.
|
||||||
|
|===
|
||||||
|
|
||||||
|
You can specify this modes through `connector-mode` parameter in connection config.
|
||||||
|
|
||||||
=== Bitcoin Methods
|
=== Bitcoin Methods
|
||||||
|
|
||||||
.By default an ethereum upstream allows call to the following JSON RPC methods:
|
.By default an ethereum upstream allows call to the following JSON RPC methods:
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package io.emeraldpay.dshackle.config
|
package io.emeraldpay.dshackle.config
|
||||||
|
|
||||||
import io.emeraldpay.dshackle.Defaults
|
import io.emeraldpay.dshackle.Defaults
|
||||||
|
import io.emeraldpay.dshackle.upstream.ethereum.connectors.EthereumConnectorFactory.ConnectorMode
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import java.util.Arrays
|
import java.util.Arrays
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
@@ -120,6 +121,23 @@ open class UpstreamsConfig {
|
|||||||
class EthereumConnection : RpcConnection() {
|
class EthereumConnection : RpcConnection() {
|
||||||
var ws: WsEndpoint? = null
|
var ws: WsEndpoint? = null
|
||||||
var preferHttp: Boolean = false
|
var preferHttp: Boolean = false
|
||||||
|
var connectorMode: String? = null
|
||||||
|
|
||||||
|
fun resolveMode(): ConnectorMode {
|
||||||
|
return if (preferHttp) {
|
||||||
|
ConnectorMode.RPC_REQUESTS_WITH_MIXED_HEAD
|
||||||
|
} else {
|
||||||
|
if (connectorMode == null) {
|
||||||
|
if (ws == null) {
|
||||||
|
ConnectorMode.RPC_ONLY
|
||||||
|
} else {
|
||||||
|
ConnectorMode.WS_ONLY
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ConnectorMode.parse(connectorMode!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BitcoinConnection : RpcConnection() {
|
class BitcoinConnection : RpcConnection() {
|
||||||
|
|||||||
@@ -186,6 +186,9 @@ class UpstreamsConfigReader(
|
|||||||
getValueAsBool(connConfigNode, "prefer-http")?.let {
|
getValueAsBool(connConfigNode, "prefer-http")?.let {
|
||||||
connection.preferHttp = it
|
connection.preferHttp = it
|
||||||
}
|
}
|
||||||
|
getValueAsString(connConfigNode, "connector-mode")?.let {
|
||||||
|
connection.connectorMode = it
|
||||||
|
}
|
||||||
getMapping(connConfigNode, "ws")?.let { node ->
|
getMapping(connConfigNode, "ws")?.let { node ->
|
||||||
getValueAsString(node, "url")?.let { url ->
|
getValueAsString(node, "url")?.let { url ->
|
||||||
val ws = UpstreamsConfig.WsEndpoint(URI(url))
|
val ws = UpstreamsConfig.WsEndpoint(URI(url))
|
||||||
|
|||||||
@@ -105,6 +105,15 @@ open class ConfiguredUpstreams(
|
|||||||
val options = (defaultOptions[chain] ?: UpstreamsConfig.Options.getDefaults())
|
val options = (defaultOptions[chain] ?: UpstreamsConfig.Options.getDefaults())
|
||||||
.merge(up.options ?: UpstreamsConfig.Options())
|
.merge(up.options ?: UpstreamsConfig.Options())
|
||||||
val upstream = when (BlockchainType.from(chain)) {
|
val upstream = when (BlockchainType.from(chain)) {
|
||||||
|
BlockchainType.EVM_POS -> {
|
||||||
|
buildEthereumPosUpstream(
|
||||||
|
up.nodeId,
|
||||||
|
up.cast(UpstreamsConfig.EthereumPosConnection::class.java),
|
||||||
|
chain,
|
||||||
|
options,
|
||||||
|
chainsConfig.resolve(chain)
|
||||||
|
)
|
||||||
|
}
|
||||||
BlockchainType.EVM_POW -> {
|
BlockchainType.EVM_POW -> {
|
||||||
buildEthereumUpstream(
|
buildEthereumUpstream(
|
||||||
up.nodeId,
|
up.nodeId,
|
||||||
@@ -114,7 +123,6 @@ open class ConfiguredUpstreams(
|
|||||||
chainsConfig.resolve(chain)
|
chainsConfig.resolve(chain)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockchainType.BITCOIN -> {
|
BlockchainType.BITCOIN -> {
|
||||||
buildBitcoinUpstream(
|
buildBitcoinUpstream(
|
||||||
up.cast(UpstreamsConfig.BitcoinConnection::class.java),
|
up.cast(UpstreamsConfig.BitcoinConnection::class.java),
|
||||||
@@ -123,16 +131,6 @@ open class ConfiguredUpstreams(
|
|||||||
chainsConfig.resolve(chain)
|
chainsConfig.resolve(chain)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockchainType.EVM_POS -> {
|
|
||||||
buildEthereumPosUpstream(
|
|
||||||
up.nodeId,
|
|
||||||
up.cast(UpstreamsConfig.EthereumPosConnection::class.java),
|
|
||||||
chain,
|
|
||||||
options,
|
|
||||||
chainsConfig.resolve(chain)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
upstream?.let {
|
upstream?.let {
|
||||||
val event = UpstreamChangeEvent(chain, upstream, UpstreamChangeEvent.ChangeType.ADDED)
|
val event = UpstreamChangeEvent(chain, upstream, UpstreamChangeEvent.ChangeType.ADDED)
|
||||||
@@ -211,7 +209,7 @@ open class ConfiguredUpstreams(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val hashUrl = conn.execution!!.let {
|
val hashUrl = conn.execution!!.let {
|
||||||
if (it.preferHttp) it.rpc?.url ?: it.ws?.url else it.ws?.url ?: it.rpc?.url
|
if (it.preferHttp == true) it.rpc?.url ?: it.ws?.url else it.ws?.url ?: it.rpc?.url
|
||||||
}
|
}
|
||||||
val hash = getHash(nodeId, hashUrl!!)
|
val hash = getHash(nodeId, hashUrl!!)
|
||||||
val upstream = EthereumPosRpcUpstream(
|
val upstream = EthereumPosRpcUpstream(
|
||||||
@@ -295,7 +293,7 @@ open class ConfiguredUpstreams(
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
val hashUrl = if (conn.preferHttp) conn.rpc?.url ?: conn.ws?.url else conn.ws?.url ?: conn.rpc?.url
|
val hashUrl = if (conn.preferHttp == true) conn.rpc?.url ?: conn.ws?.url else conn.ws?.url ?: conn.rpc?.url
|
||||||
val upstream = EthereumRpcUpstream(
|
val upstream = EthereumRpcUpstream(
|
||||||
config.id!!,
|
config.id!!,
|
||||||
getHash(nodeId, hashUrl!!),
|
getHash(nodeId, hashUrl!!),
|
||||||
@@ -399,7 +397,7 @@ open class ConfiguredUpstreams(
|
|||||||
val httpFactory = buildHttpFactory(conn, urls)
|
val httpFactory = buildHttpFactory(conn, urls)
|
||||||
log.info("Using ${chain.chainName} upstream, at ${urls.joinToString()}")
|
log.info("Using ${chain.chainName} upstream, at ${urls.joinToString()}")
|
||||||
val connectorFactory =
|
val connectorFactory =
|
||||||
EthereumConnectorFactory(conn.preferHttp, wsFactoryApi, httpFactory, forkChoice, blockValidator)
|
EthereumConnectorFactory(conn.resolveMode(), wsFactoryApi, httpFactory, forkChoice, blockValidator)
|
||||||
if (!connectorFactory.isValid()) {
|
if (!connectorFactory.isValid()) {
|
||||||
log.warn("Upstream configuration is invalid (probably no http endpoint)")
|
log.warn("Upstream configuration is invalid (probably no http endpoint)")
|
||||||
return null
|
return null
|
||||||
|
|||||||
@@ -286,7 +286,7 @@ open class WsConnectionImpl(
|
|||||||
)
|
)
|
||||||
val sender = currentRequests.remove(msg.id.asNumber().toInt())
|
val sender = currentRequests.remove(msg.id.asNumber().toInt())
|
||||||
if (sender == null) {
|
if (sender == null) {
|
||||||
log.warn("Unknown response received for ${msg.id}")
|
log.warn("Unknown response received for ${msg.id} with body ${msg.value?.let { String(it) }}")
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
val emitResult = sender.tryEmitValue(rpcResponse)
|
val emitResult = sender.tryEmitValue(rpcResponse)
|
||||||
|
|||||||
@@ -6,10 +6,14 @@ import io.emeraldpay.dshackle.upstream.DefaultUpstream
|
|||||||
import io.emeraldpay.dshackle.upstream.HttpFactory
|
import io.emeraldpay.dshackle.upstream.HttpFactory
|
||||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumUpstreamValidator
|
import io.emeraldpay.dshackle.upstream.ethereum.EthereumUpstreamValidator
|
||||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumWsConnectionPoolFactory
|
import io.emeraldpay.dshackle.upstream.ethereum.EthereumWsConnectionPoolFactory
|
||||||
|
import io.emeraldpay.dshackle.upstream.ethereum.connectors.EthereumConnectorFactory.ConnectorMode.RPC_ONLY
|
||||||
|
import io.emeraldpay.dshackle.upstream.ethereum.connectors.EthereumConnectorFactory.ConnectorMode.RPC_REQUESTS_WITH_MIXED_HEAD
|
||||||
|
import io.emeraldpay.dshackle.upstream.ethereum.connectors.EthereumConnectorFactory.ConnectorMode.RPC_REQUESTS_WITH_WS_HEAD
|
||||||
|
import io.emeraldpay.dshackle.upstream.ethereum.connectors.EthereumConnectorFactory.ConnectorMode.WS_ONLY
|
||||||
import io.emeraldpay.dshackle.upstream.forkchoice.ForkChoice
|
import io.emeraldpay.dshackle.upstream.forkchoice.ForkChoice
|
||||||
|
|
||||||
open class EthereumConnectorFactory(
|
open class EthereumConnectorFactory(
|
||||||
private val preferHttp: Boolean,
|
private val connectorType: ConnectorMode,
|
||||||
private val wsFactory: EthereumWsConnectionPoolFactory?,
|
private val wsFactory: EthereumWsConnectionPoolFactory?,
|
||||||
private val httpFactory: HttpFactory?,
|
private val httpFactory: HttpFactory?,
|
||||||
private val forkChoice: ForkChoice,
|
private val forkChoice: ForkChoice,
|
||||||
@@ -17,7 +21,20 @@ open class EthereumConnectorFactory(
|
|||||||
) : ConnectorFactory {
|
) : ConnectorFactory {
|
||||||
|
|
||||||
override fun isValid(): Boolean {
|
override fun isValid(): Boolean {
|
||||||
if (preferHttp && httpFactory == null) {
|
if ((
|
||||||
|
connectorType == RPC_ONLY ||
|
||||||
|
connectorType == RPC_REQUESTS_WITH_MIXED_HEAD ||
|
||||||
|
connectorType == RPC_REQUESTS_WITH_WS_HEAD
|
||||||
|
) && httpFactory == null
|
||||||
|
) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if ((
|
||||||
|
connectorType == WS_ONLY ||
|
||||||
|
connectorType == RPC_REQUESTS_WITH_MIXED_HEAD ||
|
||||||
|
connectorType == RPC_REQUESTS_WITH_WS_HEAD
|
||||||
|
) && wsFactory == null
|
||||||
|
) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@@ -29,13 +46,14 @@ open class EthereumConnectorFactory(
|
|||||||
chain: Chain,
|
chain: Chain,
|
||||||
skipEnhance: Boolean
|
skipEnhance: Boolean
|
||||||
): EthereumConnector {
|
): EthereumConnector {
|
||||||
if (wsFactory != null && !preferHttp) {
|
if (wsFactory != null && connectorType == WS_ONLY) {
|
||||||
return EthereumWsConnector(wsFactory, upstream, forkChoice, blockValidator, skipEnhance)
|
return EthereumWsConnector(wsFactory, upstream, forkChoice, blockValidator, skipEnhance)
|
||||||
}
|
}
|
||||||
if (httpFactory == null) {
|
if (httpFactory == null) {
|
||||||
throw java.lang.IllegalArgumentException("Can't create rpc connector if no http factory set")
|
throw java.lang.IllegalArgumentException("Can't create rpc connector if no http factory set")
|
||||||
}
|
}
|
||||||
return EthereumRpcConnector(
|
return EthereumRpcConnector(
|
||||||
|
connectorType,
|
||||||
httpFactory.create(upstream.getId(), chain),
|
httpFactory.create(upstream.getId(), chain),
|
||||||
wsFactory,
|
wsFactory,
|
||||||
upstream.getId(),
|
upstream.getId(),
|
||||||
@@ -44,4 +62,22 @@ open class EthereumConnectorFactory(
|
|||||||
skipEnhance
|
skipEnhance
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class ConnectorMode {
|
||||||
|
WS_ONLY,
|
||||||
|
RPC_ONLY,
|
||||||
|
RPC_REQUESTS_WITH_MIXED_HEAD,
|
||||||
|
RPC_REQUESTS_WITH_WS_HEAD;
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val values = values().map { it.name }.toSet()
|
||||||
|
fun parse(value: String): ConnectorMode {
|
||||||
|
val upper = value.uppercase()
|
||||||
|
if (!values.contains(upper)) {
|
||||||
|
throw IllegalArgumentException("Invalid connector mode: $value")
|
||||||
|
}
|
||||||
|
return valueOf(upper)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,12 +14,18 @@ import io.emeraldpay.dshackle.upstream.ethereum.EthereumWsHead
|
|||||||
import io.emeraldpay.dshackle.upstream.ethereum.NoEthereumIngressSubscription
|
import io.emeraldpay.dshackle.upstream.ethereum.NoEthereumIngressSubscription
|
||||||
import io.emeraldpay.dshackle.upstream.ethereum.WsConnectionPool
|
import io.emeraldpay.dshackle.upstream.ethereum.WsConnectionPool
|
||||||
import io.emeraldpay.dshackle.upstream.ethereum.WsSubscriptionsImpl
|
import io.emeraldpay.dshackle.upstream.ethereum.WsSubscriptionsImpl
|
||||||
|
import io.emeraldpay.dshackle.upstream.ethereum.connectors.EthereumConnectorFactory.ConnectorMode
|
||||||
|
import io.emeraldpay.dshackle.upstream.ethereum.connectors.EthereumConnectorFactory.ConnectorMode.RPC_ONLY
|
||||||
|
import io.emeraldpay.dshackle.upstream.ethereum.connectors.EthereumConnectorFactory.ConnectorMode.RPC_REQUESTS_WITH_MIXED_HEAD
|
||||||
|
import io.emeraldpay.dshackle.upstream.ethereum.connectors.EthereumConnectorFactory.ConnectorMode.RPC_REQUESTS_WITH_WS_HEAD
|
||||||
|
import io.emeraldpay.dshackle.upstream.ethereum.connectors.EthereumConnectorFactory.ConnectorMode.WS_ONLY
|
||||||
import io.emeraldpay.dshackle.upstream.forkchoice.AlwaysForkChoice
|
import io.emeraldpay.dshackle.upstream.forkchoice.AlwaysForkChoice
|
||||||
import io.emeraldpay.dshackle.upstream.forkchoice.ForkChoice
|
import io.emeraldpay.dshackle.upstream.forkchoice.ForkChoice
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
|
|
||||||
class EthereumRpcConnector(
|
class EthereumRpcConnector(
|
||||||
|
connectorType: ConnectorMode,
|
||||||
private val directReader: JsonRpcReader,
|
private val directReader: JsonRpcReader,
|
||||||
wsFactory: EthereumWsConnectionPoolFactory?,
|
wsFactory: EthereumWsConnectionPoolFactory?,
|
||||||
id: String,
|
id: String,
|
||||||
@@ -36,19 +42,30 @@ class EthereumRpcConnector(
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
if (wsFactory != null) {
|
if (wsFactory != null) {
|
||||||
// do not set upstream to the WS, since it doesn't control the RPC upstream
|
|
||||||
pool = wsFactory.create(null)
|
pool = wsFactory.create(null)
|
||||||
val subscriptions = WsSubscriptionsImpl(pool)
|
|
||||||
val wsHead =
|
|
||||||
EthereumWsHead(id, AlwaysForkChoice(), blockValidator, getIngressReader(), subscriptions, skipEnhance)
|
|
||||||
// receive all new blocks through WebSockets, but also periodically verify with RPC in case if WS failed
|
|
||||||
val rpcHead =
|
|
||||||
EthereumRpcHead(getIngressReader(), AlwaysForkChoice(), id, blockValidator, Duration.ofSeconds(30))
|
|
||||||
head = MergedHead(listOf(rpcHead, wsHead), forkChoice, "Merged for $id")
|
|
||||||
} else {
|
} else {
|
||||||
pool = null
|
pool = null
|
||||||
log.warn("Setting up connector for $id upstream with RPC-only access, less effective than WS+RPC")
|
}
|
||||||
head = EthereumRpcHead(getIngressReader(), forkChoice, id, blockValidator)
|
|
||||||
|
head = when (connectorType) {
|
||||||
|
RPC_ONLY -> {
|
||||||
|
log.warn("Setting up connector for $id upstream with RPC-only access, less effective than WS+RPC")
|
||||||
|
EthereumRpcHead(getIngressReader(), forkChoice, id, blockValidator)
|
||||||
|
}
|
||||||
|
WS_ONLY -> {
|
||||||
|
throw IllegalStateException("WS-only mode is not supported in RPC connector")
|
||||||
|
}
|
||||||
|
RPC_REQUESTS_WITH_MIXED_HEAD -> {
|
||||||
|
val wsHead =
|
||||||
|
EthereumWsHead(id, AlwaysForkChoice(), blockValidator, getIngressReader(), WsSubscriptionsImpl(pool!!), skipEnhance)
|
||||||
|
// receive all new blocks through WebSockets, but also periodically verify with RPC in case if WS failed
|
||||||
|
val rpcHead =
|
||||||
|
EthereumRpcHead(getIngressReader(), AlwaysForkChoice(), id, blockValidator, Duration.ofSeconds(30))
|
||||||
|
MergedHead(listOf(rpcHead, wsHead), forkChoice, "Merged for $id")
|
||||||
|
}
|
||||||
|
RPC_REQUESTS_WITH_WS_HEAD -> {
|
||||||
|
EthereumWsHead(id, AlwaysForkChoice(), blockValidator, getIngressReader(), WsSubscriptionsImpl(pool!!), skipEnhance)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ class UpstreamsConfigReaderSpec extends Specification {
|
|||||||
|
|
||||||
def "Parse ethereum pos upstreams"() {
|
def "Parse ethereum pos upstreams"() {
|
||||||
setup:
|
setup:
|
||||||
def config = this.class.getClassLoader().getResourceAsStream("upstreams-ethereum-pos.yaml")
|
def config = this.class.getClassLoader().getResourceAsStream("configs/upstreams-ethereum-pos.yaml")
|
||||||
when:
|
when:
|
||||||
def act = reader.readInternal(config)
|
def act = reader.readInternal(config)
|
||||||
then:
|
then:
|
||||||
@@ -404,7 +404,7 @@ class UpstreamsConfigReaderSpec extends Specification {
|
|||||||
|
|
||||||
def "Parse node id"() {
|
def "Parse node id"() {
|
||||||
setup:
|
setup:
|
||||||
def config = this.class.getClassLoader().getResourceAsStream("upstreams-node-id.yaml")
|
def config = this.class.getClassLoader().getResourceAsStream("configs/upstreams-node-id.yaml")
|
||||||
when:
|
when:
|
||||||
def act = reader.readInternal(config)
|
def act = reader.readInternal(config)
|
||||||
then:
|
then:
|
||||||
@@ -422,7 +422,7 @@ class UpstreamsConfigReaderSpec extends Specification {
|
|||||||
|
|
||||||
def "Parse method groups"() {
|
def "Parse method groups"() {
|
||||||
setup:
|
setup:
|
||||||
def config = this.class.getClassLoader().getResourceAsStream("upstreams-method-groups.yaml")
|
def config = this.class.getClassLoader().getResourceAsStream("configs/upstreams-method-groups.yaml")
|
||||||
when:
|
when:
|
||||||
def act = reader.readInternal(config)
|
def act = reader.readInternal(config)
|
||||||
then:
|
then:
|
||||||
@@ -459,4 +459,26 @@ class UpstreamsConfigReaderSpec extends Specification {
|
|||||||
validatePeers == true
|
validatePeers == true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def "Parse connector mode in connection config"() {
|
||||||
|
setup:
|
||||||
|
def config = this.class.getClassLoader().getResourceAsStream("configs/upstreams-connector-mode.yaml")
|
||||||
|
when:
|
||||||
|
def act = reader.readInternal(config)
|
||||||
|
then:
|
||||||
|
act != null
|
||||||
|
act.upstreams.size() == 1
|
||||||
|
with(act.upstreams.get(0)) {
|
||||||
|
id == "local"
|
||||||
|
chain == "ethereum"
|
||||||
|
connection instanceof UpstreamsConfig.EthereumConnection
|
||||||
|
with((UpstreamsConfig.EthereumConnection) connection) {
|
||||||
|
rpc != null
|
||||||
|
rpc.url == new URI("https://localhost:8546")
|
||||||
|
ws != null
|
||||||
|
ws.url == new URI("ws://localhost:8546")
|
||||||
|
connectorMode == "RPC_REQUESTS_WITH_WS_HEAD"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ class FilteredApisSpec extends Specification {
|
|||||||
def httpFactory = Mock(HttpFactory) {
|
def httpFactory = Mock(HttpFactory) {
|
||||||
create(_, _) >> TestingCommons.api().tap { it.id = "${i++}" }
|
create(_, _) >> TestingCommons.api().tap { it.id = "${i++}" }
|
||||||
}
|
}
|
||||||
def connectorFactory = new EthereumConnectorFactory(false, null, httpFactory, new MostWorkForkChoice(), BlockValidator.ALWAYS_VALID)
|
def connectorFactory = new EthereumConnectorFactory(EthereumConnectorFactory.ConnectorMode.RPC_ONLY, null, httpFactory, new MostWorkForkChoice(), BlockValidator.ALWAYS_VALID)
|
||||||
new EthereumRpcUpstream(
|
new EthereumRpcUpstream(
|
||||||
"test",
|
"test",
|
||||||
(byte)123,
|
(byte)123,
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package io.emeraldpay.dshackle.config
|
||||||
|
|
||||||
|
import io.emeraldpay.dshackle.upstream.ethereum.connectors.EthereumConnectorFactory.ConnectorMode
|
||||||
|
import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest
|
||||||
|
import org.junit.jupiter.params.provider.Arguments
|
||||||
|
import org.junit.jupiter.params.provider.MethodSource
|
||||||
|
import java.net.URI
|
||||||
|
import java.util.stream.Stream
|
||||||
|
|
||||||
|
internal class UpstreamsConfigTest {
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
fun data(): Stream<Arguments> {
|
||||||
|
return Stream.of(
|
||||||
|
Arguments.of(
|
||||||
|
UpstreamsConfig.EthereumConnection(),
|
||||||
|
ConnectorMode.RPC_ONLY
|
||||||
|
),
|
||||||
|
Arguments.of(
|
||||||
|
UpstreamsConfig.EthereumConnection()
|
||||||
|
.apply {
|
||||||
|
ws = UpstreamsConfig.WsEndpoint(URI("ws://localhost:8546"))
|
||||||
|
},
|
||||||
|
ConnectorMode.WS_ONLY
|
||||||
|
),
|
||||||
|
Arguments.of(
|
||||||
|
UpstreamsConfig.EthereumConnection()
|
||||||
|
.apply {
|
||||||
|
preferHttp = true
|
||||||
|
ws = UpstreamsConfig.WsEndpoint(URI("ws://localhost:8546"))
|
||||||
|
},
|
||||||
|
ConnectorMode.RPC_REQUESTS_WITH_MIXED_HEAD
|
||||||
|
),
|
||||||
|
Arguments.of(
|
||||||
|
UpstreamsConfig.EthereumConnection()
|
||||||
|
.apply {
|
||||||
|
connectorMode = "RPC_REQUESTS_WITH_WS_HEAD"
|
||||||
|
ws = UpstreamsConfig.WsEndpoint(URI("ws://localhost:8546"))
|
||||||
|
},
|
||||||
|
ConnectorMode.RPC_REQUESTS_WITH_WS_HEAD
|
||||||
|
),
|
||||||
|
Arguments.of(
|
||||||
|
UpstreamsConfig.EthereumConnection()
|
||||||
|
.apply {
|
||||||
|
preferHttp = true
|
||||||
|
connectorMode = "RPC_REQUESTS_WITH_WS_HEAD"
|
||||||
|
ws = UpstreamsConfig.WsEndpoint(URI("ws://localhost:8546"))
|
||||||
|
},
|
||||||
|
ConnectorMode.RPC_REQUESTS_WITH_MIXED_HEAD
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("data")
|
||||||
|
fun testKeepForwarded(input: UpstreamsConfig.EthereumConnection, expected: ConnectorMode) {
|
||||||
|
assertEquals(expected, input.resolveMode())
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/test/resources/configs/upstreams-connector-mode.yaml
Normal file
12
src/test/resources/configs/upstreams-connector-mode.yaml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
version: v1
|
||||||
|
|
||||||
|
upstreams:
|
||||||
|
- id: local
|
||||||
|
chain: ethereum
|
||||||
|
connection:
|
||||||
|
ethereum:
|
||||||
|
connector-mode: RPC_REQUESTS_WITH_WS_HEAD
|
||||||
|
ws:
|
||||||
|
url: "ws://localhost:8546"
|
||||||
|
rpc:
|
||||||
|
url: "https://localhost:8546"
|
||||||
Reference in New Issue
Block a user