diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/calls/DefaultEthereumMethods.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/calls/DefaultEthereumMethods.kt index 8c5b279f..00a140dc 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/calls/DefaultEthereumMethods.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/calls/DefaultEthereumMethods.kt @@ -22,6 +22,7 @@ import io.emeraldpay.dshackle.quorum.AlwaysQuorum import io.emeraldpay.dshackle.quorum.CallQuorum import io.emeraldpay.dshackle.quorum.NotLaggingQuorum import io.emeraldpay.dshackle.quorum.NotNullQuorum +import io.emeraldpay.dshackle.upstream.calls.DefaultEthereumMethods.HardcodedData.Companion.createHardcodedData import io.emeraldpay.etherjar.rpc.RpcException /** @@ -70,48 +71,48 @@ class DefaultEthereumMethods( ) val CHAIN_DATA = mapOf( - Chain.ETHEREUM__MAINNET to HardcodedData("\"1\"", "\"0x1\""), - Chain.ETHEREUM__RINKEBY to HardcodedData("\"4\"", "\"0x4\""), - Chain.ETHEREUM__ROPSTEN to HardcodedData("\"3\"", "\"0x3\""), - Chain.ETHEREUM__KOVAN to HardcodedData("\"42\"", "\"0x2a\""), - Chain.ETHEREUM__GOERLI to HardcodedData("\"5\"", "\"0x5\""), - Chain.ETHEREUM__SEPOLIA to HardcodedData("\"11155111\"", "\"0xaa36a7\""), + Chain.ETHEREUM__MAINNET to createHardcodedData("\"1\"", "\"0x1\""), + Chain.ETHEREUM__RINKEBY to createHardcodedData("\"4\"", "\"0x4\""), + Chain.ETHEREUM__ROPSTEN to createHardcodedData("\"3\"", "\"0x3\""), + Chain.ETHEREUM__KOVAN to createHardcodedData("\"42\"", "\"0x2a\""), + Chain.ETHEREUM__GOERLI to createHardcodedData("\"5\"", "\"0x5\""), + Chain.ETHEREUM__SEPOLIA to createHardcodedData("\"11155111\"", "\"0xaa36a7\""), - Chain.ETHEREUM_CLASSIC__MAINNET to HardcodedData("\"1\"", "\"0x3d\""), + Chain.ETHEREUM_CLASSIC__MAINNET to createHardcodedData("\"1\"", "\"0x3d\""), - Chain.POLYGON_POS__MAINNET to HardcodedData("\"137\"", "\"0x89\""), - Chain.POLYGON_POS__MUMBAI to HardcodedData("\"80001\"", "\"0x13881\""), + Chain.POLYGON_POS__MAINNET to createHardcodedData("\"137\"", "\"0x89\""), + Chain.POLYGON_POS__MUMBAI to createHardcodedData("\"80001\"", "\"0x13881\""), - Chain.ARBITRUM__MAINNET to HardcodedData("\"42161\"", "\"0xa4b1\""), - Chain.ARBITRUM__GOERLI to HardcodedData("\"421613\"", "\"0x66eed\""), + Chain.ARBITRUM__MAINNET to createHardcodedData("\"42161\"", "\"0xa4b1\""), + Chain.ARBITRUM__GOERLI to createHardcodedData("\"421613\"", "\"0x66eed\""), - Chain.OPTIMISM__MAINNET to HardcodedData("\"10\"", "\"0xa\""), - Chain.OPTIMISM__GOERLI to HardcodedData("\"420\"", "\"0x1A4\""), + Chain.OPTIMISM__MAINNET to createHardcodedData("\"10\"", "\"0xa\""), + Chain.OPTIMISM__GOERLI to createHardcodedData("\"420\"", "\"0x1A4\""), - Chain.ARBITRUM_NOVA__MAINNET to HardcodedData("\"42170\"", "\"0xa4ba\""), + Chain.ARBITRUM_NOVA__MAINNET to createHardcodedData("\"42170\"", "\"0xa4ba\""), - Chain.POLYGON_ZKEVM__MAINNET to HardcodedData("\"1101\"", "\"0x44d\""), - Chain.POLYGON_ZKEVM__TESTNET to HardcodedData("\"1442\"", "\"0x5a2\""), + Chain.POLYGON_ZKEVM__MAINNET to createHardcodedData("\"1101\"", "\"0x44d\""), + Chain.POLYGON_ZKEVM__TESTNET to createHardcodedData("\"1442\"", "\"0x5a2\""), - Chain.ZKSYNC__MAINNET to HardcodedData("\"324\"", "\"0x144\""), - Chain.ZKSYNC__TESTNET to HardcodedData("\"280\"", "\"0x118\""), + Chain.ZKSYNC__MAINNET to createHardcodedData("\"324\"", "\"0x144\""), + Chain.ZKSYNC__TESTNET to createHardcodedData("\"280\"", "\"0x118\""), - Chain.BSC__MAINNET to HardcodedData("\"56\"", "\"0x38\""), + Chain.BSC__MAINNET to createHardcodedData("\"56\"", "\"0x38\""), - Chain.BASE__MAINNET to HardcodedData("\"8453\"", "\"0x2105\""), - Chain.BASE__GOERLI to HardcodedData("\"84531\"", "\"0x14a33\""), + Chain.BASE__MAINNET to createHardcodedData("\"8453\"", "\"0x2105\""), + Chain.BASE__GOERLI to createHardcodedData("\"84531\"", "\"0x14a33\""), - Chain.LINEA__MAINNET to HardcodedData("\"59144\"", "\"0xe708\""), - Chain.LINEA__GOERLI to HardcodedData("\"59140\"", "\"0xe704\""), + Chain.LINEA__MAINNET to createHardcodedData("\"59144\"", "\"0xe708\""), + Chain.LINEA__GOERLI to createHardcodedData("\"59140\"", "\"0xe704\""), - Chain.FANTOM__MAINNET to HardcodedData("\"250\"", "\"0xfa\""), - Chain.FANTOM__TESTNET to HardcodedData("\"4002\"", "\"0xfa2\""), + Chain.FANTOM__MAINNET to createHardcodedData("\"250\"", "\"0xfa\""), + Chain.FANTOM__TESTNET to createHardcodedData("\"4002\"", "\"0xfa2\""), - Chain.GNOSIS__MAINNET to HardcodedData("\"100\"", "\"0x64\""), - Chain.GNOSIS__CHIADO to HardcodedData("\"10200\"", "\"0x27d8\""), + Chain.GNOSIS__MAINNET to createHardcodedData("\"100\"", "\"0x64\""), + Chain.GNOSIS__CHIADO to createHardcodedData("\"10200\"", "\"0x27d8\""), - Chain.AVALANCHE__MAINNET to HardcodedData("\"43114\"", "\"0xa86a\""), - Chain.AVALANCHE__FUJI to HardcodedData("\"43113\"", "\"0xa869\""), + Chain.AVALANCHE__MAINNET to createHardcodedData("\"43114\"", "\"0xa86a\""), + Chain.AVALANCHE__FUJI to createHardcodedData("\"43113\"", "\"0xa869\""), ) fun getChainByData(data: HardcodedData) = CHAIN_DATA.entries.find { it.value == data }?.key @@ -287,8 +288,6 @@ class DefaultEthereumMethods( return hardcodedMethods.contains(method) } - data class HardcodedData(val netVersion: String, val chainId: String) - override fun executeHardcoded(method: String): ByteArray { // note that the value is in json representation, i.e. if it's a string it should be with quotes, // that's why "\"0x0\"", "\"1\"", etc. But just "true" for a boolean, or "[]" for array. @@ -348,4 +347,14 @@ class DefaultEthereumMethods( override fun getSupportedMethods(): Set { return allowedMethods.plus(hardcodedMethods).toSortedSet() } + + data class HardcodedData private constructor( + val netVersion: String, + val chainId: String + ) { + companion object { + fun createHardcodedData(netVersion: String, chainId: String): HardcodedData = + HardcodedData(netVersion.lowercase(), chainId.lowercase()) + } + } } diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/ethereum/EthereumUpstreamValidator.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/ethereum/EthereumUpstreamValidator.kt index d5042c16..7a0f5c50 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/ethereum/EthereumUpstreamValidator.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/ethereum/EthereumUpstreamValidator.kt @@ -158,7 +158,7 @@ open class EthereumUpstreamValidator @JvmOverloads constructor( if (!isChainValid) { val actualChain = getChainByData( - DefaultEthereumMethods.HardcodedData(it.t2, it.t1) + DefaultEthereumMethods.HardcodedData.createHardcodedData(it.t2, it.t1) )?.chainName log.warn( "${chain.chainName} is specified for upstream ${upstream.getId()} " + @@ -194,14 +194,19 @@ open class EthereumUpstreamValidator @JvmOverloads constructor( ) ) .flatMap(JsonRpcResponse::requireResult) - .doOnError { - log.warn( - "Error: ${it.message}. Node ${upstream.getId()} is probably incorrectly configured. " + - "You need to set up your return limit to at least 200000. " + - "Erigon config example: https://github.com/ledgerwatch/erigon/blob/d014da4dc039ea97caf04ed29feb2af92b7b129d/cmd/utils/flags.go#L369 " - ) - } .map { true } + .onErrorResume { + if (it.message != null && it.message!!.contains("rpc.returndata.limit")) { + log.warn( + "Error: ${it.message}. Node ${upstream.getId()} is probably incorrectly configured. " + + "You need to set up your return limit to at least 200000. " + + "Erigon config example: https://github.com/ledgerwatch/erigon/blob/d014da4dc039ea97caf04ed29feb2af92b7b129d/cmd/utils/flags.go#L369" + ) + Mono.just(false) + } else { + Mono.error(it) + } + } .timeout( Defaults.timeoutInternal, Mono.fromCallable { log.error("No response for eth_call limit check from ${upstream.getId()}") } @@ -209,8 +214,8 @@ open class EthereumUpstreamValidator @JvmOverloads constructor( ) .retryRandomBackoff(3, Duration.ofMillis(100), Duration.ofMillis(500)) { ctx -> log.warn( - "error during validateCallLimit for ${upstream.getId()}, iteration ${ctx.iteration()}", - ctx.exception() + "error during validateCallLimit for ${upstream.getId()}, iteration ${ctx.iteration()}, " + + "message ${ctx.exception().message}" ) } .onErrorReturn(false) @@ -226,8 +231,8 @@ open class EthereumUpstreamValidator @JvmOverloads constructor( } .retryRandomBackoff(3, Duration.ofMillis(100), Duration.ofMillis(500)) { ctx -> log.warn( - "error during old block retrieving for ${upstream.getId()}, iteration ${ctx.iteration()}", - ctx.exception() + "error during old block retrieving for ${upstream.getId()}, iteration ${ctx.iteration()}, " + + "message ${ctx.exception().message}" ) } .map { result -> @@ -250,8 +255,8 @@ open class EthereumUpstreamValidator @JvmOverloads constructor( .read(JsonRpcRequest("eth_chainId", emptyList())) .retryRandomBackoff(3, Duration.ofMillis(100), Duration.ofMillis(500)) { ctx -> log.warn( - "error during chainId retrieving for ${upstream.getId()}, iteration ${ctx.iteration()}", - ctx.exception() + "error during chainId retrieving for ${upstream.getId()}, iteration ${ctx.iteration()}, " + + "message ${ctx.exception().message}" ) } .doOnError { log.error("Error during execution 'eth_chainId' - ${it.message} for ${upstream.getId()}") } @@ -264,8 +269,8 @@ open class EthereumUpstreamValidator @JvmOverloads constructor( .read(JsonRpcRequest("net_version", emptyList())) .retryRandomBackoff(3, Duration.ofMillis(100), Duration.ofMillis(500)) { ctx -> log.warn( - "error during netVersion retrieving for ${upstream.getId()}, iteration ${ctx.iteration()}", - ctx.exception() + "error during netVersion retrieving for ${upstream.getId()}, iteration ${ctx.iteration()}, " + + "message ${ctx.exception().message}" ) } .doOnError { log.error("Error during execution 'net_version' - ${it.message} for ${upstream.getId()}") } diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/rpcclient/JsonRpcHttpClient.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/rpcclient/JsonRpcHttpClient.kt index 6c511e8b..188fac9e 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/rpcclient/JsonRpcHttpClient.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/rpcclient/JsonRpcHttpClient.kt @@ -112,7 +112,11 @@ class JsonRpcHttpClient( val startTime = StopWatch() return Mono.just(key) .map(JsonRpcRequest::toJson) - .doOnNext { startTime.start() } + .doOnNext { + if (!startTime.isStarted) { + startTime.start() + } + } .flatMap(this@JsonRpcHttpClient::execute) .doOnNext { if (startTime.isStarted) {