From c0a9f80478f0767318a19a883639d8ac97f01b14 Mon Sep 17 00:00:00 2001 From: Andrey Bronin Date: Wed, 2 Apr 2025 12:12:10 +0300 Subject: [PATCH] support eth_simulateV1 for all EVM node types (#645) * support eth_simulateV1 for all EVM node types * eth_simulateV1 detector * eth_simulateV1 rewrite detector with special error * eth_simulateV1 add invalid params error as valid * build fix * fix eth_simulateV1 detector behavior * detect as true log message --------- Co-authored-by: Andrey Bronin --- .../upstream/UpstreamRpcMethodsDetector.kt | 18 +++++++++-- .../BasicEthUpstreamRpcMethodsDetector.kt | 1 + .../BasicEthUpstreamRpcMethodsDetectorTest.kt | 30 ++++++++++++++++++- 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/UpstreamRpcMethodsDetector.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/UpstreamRpcMethodsDetector.kt index 5b6c3981..215f3faf 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/UpstreamRpcMethodsDetector.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/UpstreamRpcMethodsDetector.kt @@ -18,10 +18,16 @@ abstract class UpstreamRpcMethodsDetector( listOf( "method ([A-Za-z0-9_]+) does not exist/is not available", "([A-Za-z0-9_]+) found but the containing module is disabled", - "Method not found", + "[Mm]ethod not found", "The method ([A-Za-z0-9_]+) is not available", ).map { s -> s.toRegex() } + private val availableRegexps = + listOf( + "missing value for required argument ([0-9]+)", + "Invalid params", + ).map { s -> s.toRegex() } + open fun detectRpcMethods(): Mono> = detectByMagicMethod().switchIfEmpty(detectByMethod()) protected fun detectByMethod(): Mono> = @@ -38,9 +44,15 @@ abstract class UpstreamRpcMethodsDetector( method to true } .onErrorResume { err -> - val notAvailableError = + val methodAvailableError = + availableRegexps.any { s -> s.containsMatchIn(err.message ?: "") } + val methodNotAvailableError = notAvailableRegexps.any { s -> s.containsMatchIn(err.message ?: "") } - if (notAvailableError) { + + if (methodAvailableError) { + log.error("$method failed with ${err.message}, detect as true") + Mono.just(method to true) + } else if (methodNotAvailableError) { log.error("$method failed with ${err.message}, detect as false") Mono.just(method to false) } else { diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/ethereum/BasicEthUpstreamRpcMethodsDetector.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/ethereum/BasicEthUpstreamRpcMethodsDetector.kt index acc3a525..bf81b4ed 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/ethereum/BasicEthUpstreamRpcMethodsDetector.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/ethereum/BasicEthUpstreamRpcMethodsDetector.kt @@ -34,6 +34,7 @@ class BasicEthUpstreamRpcMethodsDetector( setOf( "eth_getBlockReceipts" to ListParams("latest"), "trace_callMany" to ListParams(listOf(listOf())), + "eth_simulateV1" to ListParams(listOf(listOf())), ) private fun parseRpcModules(data: ByteArray): Map { diff --git a/src/test/kotlin/io/emeraldpay/dshackle/upstream/ethereum/BasicEthUpstreamRpcMethodsDetectorTest.kt b/src/test/kotlin/io/emeraldpay/dshackle/upstream/ethereum/BasicEthUpstreamRpcMethodsDetectorTest.kt index 3951ceca..f183b22e 100644 --- a/src/test/kotlin/io/emeraldpay/dshackle/upstream/ethereum/BasicEthUpstreamRpcMethodsDetectorTest.kt +++ b/src/test/kotlin/io/emeraldpay/dshackle/upstream/ethereum/BasicEthUpstreamRpcMethodsDetectorTest.kt @@ -48,6 +48,15 @@ class BasicEthUpstreamRpcMethodsDetectorTest { null, ), ) + on { + read(ChainRequest("eth_simulateV1", ListParams(listOf(listOf())))) + } doReturn + Mono.just( + ChainResponse( + "[]".toByteArray(), + null, + ), + ) } val upstream = @@ -97,6 +106,15 @@ class BasicEthUpstreamRpcMethodsDetectorTest { null, ), ) + on { + read(ChainRequest("eth_simulateV1", ListParams(listOf(listOf())))) + } doReturn + Mono.just( + ChainResponse( + "[]".toByteArray(), + null, + ), + ) } val upstream = @@ -108,7 +126,7 @@ class BasicEthUpstreamRpcMethodsDetectorTest { val detector = BasicEthUpstreamRpcMethodsDetector(upstream, config) Assertions.assertThat(detector.detectRpcMethods().block()).apply { isNotNull() - hasSize(2) + hasSize(3) containsEntry("eth_getBlockReceipts", true) containsEntry("trace_callMany", true) } @@ -147,6 +165,15 @@ class BasicEthUpstreamRpcMethodsDetectorTest { null, ), ) + on { + read(ChainRequest("eth_simulateV1", ListParams(listOf(listOf())))) + } doReturn + Mono.just( + ChainResponse( + null, + ChainCallError(32602, "missing value for required argument 0"), + ), + ) } val upstream = @@ -168,6 +195,7 @@ class BasicEthUpstreamRpcMethodsDetectorTest { containsEntry("eth_getBlockByNumber", false) containsEntry("eth_getBlockReceipts", true) containsEntry("debug_traceBlock", true) + containsEntry("eth_simulateV1", true) } } }