Autodetect methods (#562)

* Autodetect methods

* add polkadot magic method detection

* fix lint

* change config.methods writing

* fix log

* change Flux to Mono.zip

* change block to subscribe

* split chain method detectors

* eth method detector use rpc_modules

* rm UpstreamRpcModulesDetector.kt

* add tests

* getAllMethods for eth

* prefer enable/disable methods from config

* update tests

* whiter list & full is not available error check

* prefer config method group

* mv notAvailableRegexps to class variable
This commit is contained in:
Anton
2024-09-11 15:58:47 +03:00
committed by GitHub
parent 5fd26acf1b
commit 5fe044bba6
13 changed files with 468 additions and 97 deletions

View File

@@ -0,0 +1,145 @@
package io.emeraldpay.dshackle.upstream.ethereum
import io.emeraldpay.dshackle.Chain
import io.emeraldpay.dshackle.config.UpstreamsConfig
import io.emeraldpay.dshackle.reader.ChainReader
import io.emeraldpay.dshackle.upstream.ChainCallError
import io.emeraldpay.dshackle.upstream.ChainRequest
import io.emeraldpay.dshackle.upstream.ChainResponse
import io.emeraldpay.dshackle.upstream.Upstream
import io.emeraldpay.dshackle.upstream.rpcclient.ListParams
import org.assertj.core.api.Assertions
import org.junit.jupiter.api.Test
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import reactor.core.publisher.Mono
class BasicEthUpstreamRpcMethodsDetectorTest {
@Test
fun `rpc_modules without web3 and eth_getBlockReceipts`() {
val reader =
mock<ChainReader> {
on {
read(ChainRequest("rpc_modules", ListParams()))
} doReturn
Mono.just(
ChainResponse(
"""{"net": "1.0","debug": "1.0","txpool": "1.0","drpc": "1.0","erigon": "1.0","eth": "1.0","trace": "1.0"}"""
.toByteArray(),
null,
),
)
on {
read(ChainRequest("eth_getBlockReceipts", ListParams("latest")))
} doReturn
Mono.just(
ChainResponse(
"""[{"blockHash": "0xd12897f54acaa79f4824aa4f8e1d0f045b5568f5b942073555e9977202c5c474","blockNumber": "0x13c1108"}]"""
.toByteArray(),
null,
),
)
}
val upstream =
mock<Upstream> {
on { getIngressReader() } doReturn reader
on { getChain() } doReturn Chain.ETHEREUM__MAINNET
}
val config = mock<UpstreamsConfig.Upstream<*>> { }
val detector = BasicEthUpstreamRpcMethodsDetector(upstream, config)
Assertions.assertThat(detector.detectRpcMethods().block()).apply {
isNotNull()
size().isGreaterThanOrEqualTo(2)
containsEntry("web3_clientVersion", false)
containsValues(true)
}
}
@Test
fun `rpc_modules disabled and eth_getBlockReceipts`() {
val reader =
mock<ChainReader> {
on {
read(ChainRequest("rpc_modules", ListParams()))
} doReturn
Mono.just(
ChainResponse(
null,
ChainCallError(32601, "the method rpc_modules does not exist/is not available"),
),
)
on {
read(ChainRequest("eth_getBlockReceipts", ListParams("latest")))
} doReturn
Mono.just(
ChainResponse(
"""[{"blockHash": "0xd12897f54acaa79f4824aa4f8e1d0f045b5568f5b942073555e9977202c5c474","blockNumber": "0x13c1108"}]"""
.toByteArray(),
null,
),
)
}
val upstream =
mock<Upstream> {
on { getIngressReader() } doReturn reader
on { getChain() } doReturn Chain.ETHEREUM__MAINNET
}
val config = mock<UpstreamsConfig.Upstream<*>> { }
val detector = BasicEthUpstreamRpcMethodsDetector(upstream, config)
Assertions.assertThat(detector.detectRpcMethods().block()).apply {
isNotNull()
hasSize(1)
containsEntry("eth_getBlockReceipts", true)
}
}
@Test
fun `prefer local config methods group`() {
val reader =
mock<ChainReader> {
on {
read(ChainRequest("rpc_modules", ListParams()))
} doReturn
Mono.just(
ChainResponse(
"""{"net": "1.0","debug": "1.0","txpool": "1.0","drpc": "1.0","erigon": "1.0","eth": "1.0","trace": "1.0"}"""
.toByteArray(),
null,
),
)
on {
read(ChainRequest("eth_getBlockReceipts", ListParams("latest")))
} doReturn
Mono.just(
ChainResponse(
"""[{"blockHash": "0xd12897f54acaa79f4824aa4f8e1d0f045b5568f5b942073555e9977202c5c474","blockNumber": "0x13c1108"}]"""
.toByteArray(),
null,
),
)
}
val upstream =
mock<Upstream> {
on { getIngressReader() } doReturn reader
on { getChain() } doReturn Chain.ETHEREUM__MAINNET
}
val config =
mock<UpstreamsConfig.Upstream<*>> {
on { methodGroups } doReturn
UpstreamsConfig.MethodGroups(
emptySet(),
setOf("eth"),
)
}
val detector = BasicEthUpstreamRpcMethodsDetector(upstream, config)
Assertions.assertThat(detector.detectRpcMethods().block()).apply {
isNotNull()
containsEntry("eth_getBlockByNumber", false)
containsEntry("eth_getBlockReceipts", true)
containsEntry("debug_traceBlock", true)
}
}
}

View File

@@ -0,0 +1,69 @@
package io.emeraldpay.dshackle.upstream.polkadot
import io.emeraldpay.dshackle.Chain
import io.emeraldpay.dshackle.reader.ChainReader
import io.emeraldpay.dshackle.upstream.ChainCallError
import io.emeraldpay.dshackle.upstream.ChainRequest
import io.emeraldpay.dshackle.upstream.ChainResponse
import io.emeraldpay.dshackle.upstream.Upstream
import io.emeraldpay.dshackle.upstream.rpcclient.ListParams
import org.assertj.core.api.Assertions
import org.junit.jupiter.api.Test
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import reactor.core.publisher.Mono
class BasicPolkadotUpstreamRpcMethodsDetectorTest {
@Test
fun `rpc_methods enabled`() {
val reader =
mock<ChainReader> {
on {
read(ChainRequest("rpc_methods", ListParams()))
} doReturn
Mono.just(
ChainResponse(
""" {"methods": ["account_nextIndex","archive_unstable_body","archive_unstable_call"]}"""
.toByteArray(),
null,
),
)
}
val upstream =
mock<Upstream> {
on { getIngressReader() } doReturn reader
on { getChain() } doReturn Chain.POLKADOT__MAINNET
}
val detector = BasicPolkadotUpstreamRpcMethodsDetector(upstream)
Assertions.assertThat(detector.detectRpcMethods().block()).apply {
isNotNull()
hasSize(3)
containsKeys("account_nextIndex", "archive_unstable_body", "archive_unstable_call")
}
}
@Test
fun `rpc_methods disabled`() {
val reader =
mock<ChainReader> {
on {
read(ChainRequest("rpc_methods", ListParams()))
} doReturn
Mono.just(
ChainResponse(
null,
ChainCallError(32601, "the method rpc_methods does not exist/is not available"),
),
)
}
val upstream =
mock<Upstream> {
on { getIngressReader() } doReturn reader
on { getChain() } doReturn Chain.POLKADOT__MAINNET
}
val detector = BasicPolkadotUpstreamRpcMethodsDetector(upstream)
Assertions.assertThat(detector.detectRpcMethods().block()).isNull()
}
}