You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tuweni.apache.org by to...@apache.org on 2021/08/03 03:46:23 UTC

[incubator-tuweni] branch main updated: Fixes to make the JSON-RPC proxy work well

This is an automated email from the ASF dual-hosted git repository.

toulmean pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-tuweni.git


The following commit(s) were added to refs/heads/main by this push:
     new 25b49a4  Fixes to make the JSON-RPC proxy work well
     new 50d3bdf  Merge pull request #332 from atoulme/jsonrpc_fixes
25b49a4 is described below

commit 25b49a47d1655b42f1aa910e4b49ec517545bcc2
Author: Antoine Toulme <an...@lunar-ocean.com>
AuthorDate: Mon Aug 2 14:43:50 2021 -0700

    Fixes to make the JSON-RPC proxy work well
---
 app-commons/build.gradle                           |  4 +-
 .../tuweni/faucet/controller/FaucetController.kt   |  2 +-
 .../org/apache/tuweni/eth/JSONRPCResponse.kt       |  2 +-
 .../org/apache/tuweni/jsonrpc/app/JSONRPCApp.kt    | 30 ++++++------
 .../org/apache/tuweni/jsonrpc/app/JSONRPCConfig.kt | 14 +++---
 jsonrpc-app/src/main/resources/logback.xml         | 27 +++++++++++
 .../org/apache/tuweni/jsonrpc/JSONRPCClient.kt     |  5 +-
 .../org/apache/tuweni/jsonrpc/JSONRPCServer.kt     | 47 +++++++++++--------
 .../tuweni/jsonrpc/methods/MethodsHandler.kt       | 53 +++++++++++++---------
 .../org/apache/tuweni/jsonrpc/methods/Web3.kt      |  4 +-
 .../org/apache/tuweni/jsonrpc/JSONRPCClientTest.kt |  8 ++--
 .../org/apache/tuweni/jsonrpc/JSONRPCServerTest.kt |  8 ++--
 .../tuweni/jsonrpc/methods/MethodsHandlerTest.kt   | 14 +++---
 13 files changed, 134 insertions(+), 84 deletions(-)

diff --git a/app-commons/build.gradle b/app-commons/build.gradle
index b562ab4..f1a9b8b 100644
--- a/app-commons/build.gradle
+++ b/app-commons/build.gradle
@@ -33,10 +33,10 @@ def copyrightHeader = """
 """
 
 processResources {
-  doFirst {
+  doLast {
     def resourcesDir = sourceSets.main.output.resourcesDir
     resourcesDir.mkdirs()
-    def contents = "copyrightHeader\r\nversion=$rootProject.version"
+    def contents = "$copyrightHeader\r\nversion=$rootProject.version"
     new File(resourcesDir, "project-info.properties").text = contents
   }
 }
diff --git a/eth-faucet/src/main/kotlin/org/apache/tuweni/faucet/controller/FaucetController.kt b/eth-faucet/src/main/kotlin/org/apache/tuweni/faucet/controller/FaucetController.kt
index c1cb56a..cb12471 100644
--- a/eth-faucet/src/main/kotlin/org/apache/tuweni/faucet/controller/FaucetController.kt
+++ b/eth-faucet/src/main/kotlin/org/apache/tuweni/faucet/controller/FaucetController.kt
@@ -63,7 +63,7 @@ class FaucetController(@Autowired val vertx: Vertx, @Autowired val wallet: Walle
 
   @PostConstruct
   fun createClient() {
-    jsonrpcClient = JSONRPCClient(vertx, rpcPort!!, rpcHost!!)
+    jsonrpcClient = JSONRPCClient(vertx, "http://$rpcHost:$rpcPort")
   }
 
   @GetMapping("/")
diff --git a/eth/src/main/kotlin/org/apache/tuweni/eth/JSONRPCResponse.kt b/eth/src/main/kotlin/org/apache/tuweni/eth/JSONRPCResponse.kt
index 3f80a21..203587e 100644
--- a/eth/src/main/kotlin/org/apache/tuweni/eth/JSONRPCResponse.kt
+++ b/eth/src/main/kotlin/org/apache/tuweni/eth/JSONRPCResponse.kt
@@ -20,7 +20,7 @@ import com.fasterxml.jackson.annotation.JsonInclude
 import com.fasterxml.jackson.annotation.JsonProperty
 
 @JsonInclude(JsonInclude.Include.NON_NULL)
-data class JSONRPCResponse(@JsonProperty("id") val id: Int, @JsonProperty("result") val result: Any? = null, @JsonProperty("error") val error: JSONRPCError? = null)
+data class JSONRPCResponse(@JsonProperty("id") val id: Int, @JsonProperty("result") val result: Any? = null, @JsonProperty("error") val error: JSONRPCError? = null, @JsonProperty("jsonrpc") val jsonrpc: String = "2.0")
 
 data class JSONRPCError(@JsonProperty("code") val code: Int, @JsonProperty("message") val message: String)
 
diff --git a/jsonrpc-app/src/main/kotlin/org/apache/tuweni/jsonrpc/app/JSONRPCApp.kt b/jsonrpc-app/src/main/kotlin/org/apache/tuweni/jsonrpc/app/JSONRPCApp.kt
index 90f448d..2edb44a 100644
--- a/jsonrpc-app/src/main/kotlin/org/apache/tuweni/jsonrpc/app/JSONRPCApp.kt
+++ b/jsonrpc-app/src/main/kotlin/org/apache/tuweni/jsonrpc/app/JSONRPCApp.kt
@@ -20,6 +20,8 @@ import com.fasterxml.jackson.databind.ObjectMapper
 import io.vertx.core.Vertx
 import io.vertx.core.VertxOptions
 import io.vertx.tracing.opentelemetry.OpenTelemetryOptions
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.asCoroutineDispatcher
 import kotlinx.coroutines.runBlocking
 import org.apache.tuweni.app.commons.ApplicationUtils
@@ -51,6 +53,7 @@ import org.slf4j.LoggerFactory
 import java.nio.file.Paths
 import java.security.Security
 import java.util.concurrent.Executors
+import kotlin.coroutines.CoroutineContext
 import kotlin.system.exitProcess
 
 val logger = LoggerFactory.getLogger(JSONRPCApp::class.java)
@@ -97,22 +100,22 @@ object JSONRPCApp {
 class JSONRPCApplication(
   val vertx: Vertx,
   val config: JSONRPCConfig,
-  val metricsService: MetricsService
-) {
+  val metricsService: MetricsService,
+  override val coroutineContext: CoroutineContext = Dispatchers.Unconfined,
+) : CoroutineScope {
 
   fun run() {
-    val client = JSONRPCClient(vertx, config.endpointPort(), config.endpointHost(), basicAuthenticationEnabled = config.endpointBasicAuthEnabled(), basicAuthenticationUsername = config.endpointBasicAuthUsername(), basicAuthenticationPassword = config.endpointBasicAuthPassword())
+    logger.info("JSON-RPC proxy starting")
+    val client = JSONRPCClient(vertx, config.endpointUrl(), basicAuthenticationEnabled = config.endpointBasicAuthEnabled(), basicAuthenticationUsername = config.endpointBasicAuthUsername(), basicAuthenticationPassword = config.endpointBasicAuthPassword())
     // TODO allow more options such as allowlist of certificates, enforce client authentication.
     val trustOptions = VertxTrustOptions.recordClientFingerprints(config.clientFingerprintsFile())
 
     val allowListHandler = MethodAllowListHandler(config.allowedMethods()) { req ->
-      runBlocking {
-        try {
-          client.sendRequest(req).await()
-        } catch (e: Exception) {
-          logger.error("Error sending JSON-RPC request", e)
-          internalError.copy(id = req.id)
-        }
+      try {
+        client.sendRequest(req).await()
+      } catch (e: Exception) {
+        logger.error("Error sending JSON-RPC request", e)
+        internalError.copy(id = req.id)
       }
     }
 
@@ -127,7 +130,8 @@ class JSONRPCApplication(
       val cache: Cache<String, JSONRPCResponse> = manager.createCache(
         "responses",
         ConfigurationBuilder().persistence().addStore(RocksDBStoreConfigurationBuilder::class.java)
-          .location(config.cacheStoragePath()).build()
+          .location(Paths.get(config.cacheStoragePath(), "storage").toAbsolutePath().toString())
+          .expiredLocation(Paths.get(config.cacheStoragePath(), "expired").toAbsolutePath().toString()).build()
       )
 
       val cachingHandler =
@@ -161,13 +165,13 @@ class JSONRPCApplication(
     Runtime.getRuntime().addShutdownHook(
       Thread {
         runBlocking {
-          server.stop().await()
+          server.stop()
           client.close()
         }
       }
     )
     runBlocking {
-      server.start().await()
+      server.start()
       logger.info("JSON-RPC server started")
     }
   }
diff --git a/jsonrpc-app/src/main/kotlin/org/apache/tuweni/jsonrpc/app/JSONRPCConfig.kt b/jsonrpc-app/src/main/kotlin/org/apache/tuweni/jsonrpc/app/JSONRPCConfig.kt
index 49c1705..dea8476 100644
--- a/jsonrpc-app/src/main/kotlin/org/apache/tuweni/jsonrpc/app/JSONRPCConfig.kt
+++ b/jsonrpc-app/src/main/kotlin/org/apache/tuweni/jsonrpc/app/JSONRPCConfig.kt
@@ -36,19 +36,18 @@ class JSONRPCConfig(val filePath: Path) {
       .addString("metricsNetworkInterface", "localhost", "Metric service network interface", null)
       .addBoolean("metricsGrpcPushEnabled", false, "Enable pushing metrics to gRPC service", null)
       .addBoolean("metricsPrometheusEnabled", false, "Enable exposing metrics on the Prometheus endpoint", null)
-      .addInteger("port", 8845, "JSON-RPC server port", PropertyValidator.isValidPort())
+      .addInteger("port", 8545, "JSON-RPC server port", PropertyValidator.isValidPort())
       .addString("networkInterface", "127.0.0.1", "JSON-RPC server network interface", null)
       .addString("clientFingerprintsFile", "fingerprints.txt", "File recording client connection fingerprints", null)
       .addBoolean("ssl", false, "Whether the JSON-RPC server should serve data over SSL", null)
       .addBoolean("basicAuth", false, "Whether the JSON-RPC server should authenticate incoming requests with HTTP Basic Authentication", null)
-      .addString("basicAuthUsername", null, "HTTP Basic Auth username", null)
-      .addString("basicAuthPassword", null, "HTTP Basic Auth password", null)
-      .addString("basicAuthRealm", null, "HTTP Basic Auth realm", null)
+      .addString("basicAuthUsername", "", "HTTP Basic Auth username", null)
+      .addString("basicAuthPassword", "", "HTTP Basic Auth password", null)
+      .addString("basicAuthRealm", "Apache Tuweni JSON-RPC proxy", "HTTP Basic Auth realm", null)
       .addListOfString("allowedMethods", Collections.emptyList(), "Allowed JSON-RPC methods", null)
       .addListOfString("allowedRanges", Collections.singletonList("0.0.0.0/0"), "Allowed IP ranges", null)
       .addListOfString("rejectedRanges", Collections.emptyList(), "Rejected IP ranges", null)
-      .addInteger("endpointPort", 8545, "JSON-RPC endpoint port", PropertyValidator.isValidPort())
-      .addString("endpointHost", "localhost", "JSON-RPC endpoint host", null)
+      .addString("endpointUrl", "http://localhost:8545", "JSON-RPC endpoint", null)
       .addBoolean("endpointBasicAuthEnabled", false, "Enable basic authentication for the endpoint", null)
       .addString("endpointBasicAuthUsername", "", "Basic authentication username for the endpoint", null)
       .addString("endpointBasicAuthPassword", "", "Basic authentication password for the endpoint", null)
@@ -79,8 +78,7 @@ class JSONRPCConfig(val filePath: Path) {
   fun allowedRanges() = config.getListOfString("allowedRanges")
   fun rejectedRanges() = config.getListOfString("rejectedRanges")
 
-  fun endpointPort() = config.getInteger("endpointPort")
-  fun endpointHost() = config.getString("endpointHost")
+  fun endpointUrl() = config.getString("endpointUrl")
 
   fun endpointBasicAuthEnabled() = config.getBoolean("endpointBasicAuthEnabled")
   fun endpointBasicAuthUsername() = config.getString("endpointBasicAuthUsername")
diff --git a/jsonrpc-app/src/main/resources/logback.xml b/jsonrpc-app/src/main/resources/logback.xml
new file mode 100644
index 0000000..a13e46b
--- /dev/null
+++ b/jsonrpc-app/src/main/resources/logback.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE
+ file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file
+ to You 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.
+-->
+<configuration>
+
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+        <!-- encoders are assigned the type
+             ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
+        <encoder>
+            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
+        </encoder>
+    </appender>
+
+    <root level="trace">
+        <appender-ref ref="STDOUT" />
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/jsonrpc/src/main/kotlin/org/apache/tuweni/jsonrpc/JSONRPCClient.kt b/jsonrpc/src/main/kotlin/org/apache/tuweni/jsonrpc/JSONRPCClient.kt
index 8389388..d2dbdf1 100644
--- a/jsonrpc/src/main/kotlin/org/apache/tuweni/jsonrpc/JSONRPCClient.kt
+++ b/jsonrpc/src/main/kotlin/org/apache/tuweni/jsonrpc/JSONRPCClient.kt
@@ -40,8 +40,7 @@ val mapper = ObjectMapper()
  */
 class JSONRPCClient(
   vertx: Vertx,
-  val serverPort: Int,
-  val serverHost: String,
+  val endpointUrl: String,
   val userAgent: String = "Apache Tuweni JSON-RPC Client",
   val basicAuthenticationEnabled: Boolean = false,
   val basicAuthenticationUsername: String = "",
@@ -54,7 +53,7 @@ class JSONRPCClient(
 
   suspend fun sendRequest(request: JSONRPCRequest): Deferred<JSONRPCResponse> {
     val deferred = CompletableDeferred<JSONRPCResponse>()
-    val httpRequest = client.post(serverPort, serverHost, "/")
+    val httpRequest = client.postAbs(endpointUrl)
       .putHeader("Content-Type", "application/json")
 
     if (basicAuthenticationEnabled) {
diff --git a/jsonrpc/src/main/kotlin/org/apache/tuweni/jsonrpc/JSONRPCServer.kt b/jsonrpc/src/main/kotlin/org/apache/tuweni/jsonrpc/JSONRPCServer.kt
index 1a05e89..7ba0419 100644
--- a/jsonrpc/src/main/kotlin/org/apache/tuweni/jsonrpc/JSONRPCServer.kt
+++ b/jsonrpc/src/main/kotlin/org/apache/tuweni/jsonrpc/JSONRPCServer.kt
@@ -37,12 +37,14 @@ import io.vertx.ext.web.handler.BasicAuthHandler
 import io.vertx.ext.web.handler.SessionHandler
 import io.vertx.ext.web.sstore.LocalSessionStore
 import io.vertx.kotlin.coroutines.await
+import io.vertx.kotlin.coroutines.dispatcher
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Deferred
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.async
 import kotlinx.coroutines.awaitAll
-import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.launch
 import org.apache.tuweni.eth.JSONRPCRequest
 import org.apache.tuweni.eth.JSONRPCResponse
 import org.apache.tuweni.eth.internalError
@@ -65,7 +67,7 @@ class JSONRPCServer(
   val basicAuthRealm: String = "Apache Tuweni JSON-RPC proxy",
   val ipRangeChecker: IPRangeChecker = IPRangeChecker.allowAll(),
   override val coroutineContext: CoroutineContext = Dispatchers.Default,
-  val methodHandler: (JSONRPCRequest) -> JSONRPCResponse,
+  val methodHandler: suspend (JSONRPCRequest) -> JSONRPCResponse,
 ) : CoroutineScope {
 
   companion object {
@@ -90,12 +92,12 @@ class JSONRPCServer(
     }
   }
 
-  fun start() = async {
+  suspend fun start() {
     val serverOptions = HttpServerOptions().setPort(port).setHost(networkInterface).setSsl(ssl).setTracingPolicy(TracingPolicy.ALWAYS)
     trustOptions?.let {
       serverOptions.setTrustOptions(it)
     }
-    httpServer = vertx.createHttpServer()
+    httpServer = vertx.createHttpServer(serverOptions)
     httpServer?.connectionHandler {
       val remoteAddress = it.remoteAddress().hostAddress()
       if (!ipRangeChecker.check(remoteAddress)) {
@@ -131,20 +133,25 @@ class JSONRPCServer(
         httpRequest.response().end(mapper.writeValueAsString(internalError))
       }
       httpRequest.bodyHandler {
-        val responses = mutableListOf<Deferred<JSONRPCResponse>>()
-        val requests: Array<JSONRPCRequest>
+        var requests: Array<JSONRPCRequest>
         try {
           requests = mapper.readerFor(Array<JSONRPCRequest>::class.java).readValue(it.bytes)
         } catch (e: IOException) {
-          logger.warn("Invalid request", e)
-          httpRequest.response().end(mapper.writeValueAsString(parseError))
-          return@bodyHandler
-        }
-        for (request in requests) {
-          responses.add(handleRequest(request))
+          try {
+            requests = arrayOf(mapper.readerFor(JSONRPCRequest::class.java).readValue(it.bytes))
+          } catch (e: IOException) {
+            logger.warn("Invalid request", e)
+            httpRequest.response().end(mapper.writeValueAsString(parseError))
+            return@bodyHandler
+          }
         }
-        // TODO replace with launch.
-        runBlocking {
+
+        launch(vertx.dispatcher()) {
+          val responses = mutableListOf<Deferred<JSONRPCResponse>>()
+          for (request in requests) {
+            logger.trace("Request {}", request)
+            responses.add(handleRequest(request))
+          }
           val readyResponses = responses.awaitAll()
           if (readyResponses.size == 1) {
             httpRequest.response().end(mapper.writeValueAsString(readyResponses.get(0)))
@@ -156,13 +163,17 @@ class JSONRPCServer(
     }
     httpServer?.requestHandler(router)
     httpServer?.listen()?.await()
+    logger.info("Started JSON-RPC server on $networkInterface:${port()}")
   }
 
-  private fun handleRequest(request: JSONRPCRequest): Deferred<JSONRPCResponse> = async {
-    methodHandler(request)
-  }
+  private suspend fun handleRequest(request: JSONRPCRequest): Deferred<JSONRPCResponse> =
+    coroutineScope {
+      async {
+        methodHandler(request)
+      }
+    }
 
-  fun stop() = async {
+  suspend fun stop() {
     httpServer?.close()?.await()
   }
 
diff --git a/jsonrpc/src/main/kotlin/org/apache/tuweni/jsonrpc/methods/MethodsHandler.kt b/jsonrpc/src/main/kotlin/org/apache/tuweni/jsonrpc/methods/MethodsHandler.kt
index 81cd4a0..0eb7e99 100644
--- a/jsonrpc/src/main/kotlin/org/apache/tuweni/jsonrpc/methods/MethodsHandler.kt
+++ b/jsonrpc/src/main/kotlin/org/apache/tuweni/jsonrpc/methods/MethodsHandler.kt
@@ -20,7 +20,6 @@ import com.netflix.concurrency.limits.limit.FixedLimit
 import com.netflix.concurrency.limits.limiter.SimpleLimiter
 import io.opentelemetry.api.metrics.LongCounter
 import io.opentelemetry.api.metrics.common.Labels
-import kotlinx.coroutines.runBlocking
 import org.apache.tuweni.eth.JSONRPCRequest
 import org.apache.tuweni.eth.JSONRPCResponse
 import org.apache.tuweni.eth.methodNotEnabled
@@ -28,9 +27,9 @@ import org.apache.tuweni.eth.methodNotFound
 import org.apache.tuweni.eth.tooManyRequests
 import org.apache.tuweni.kv.KeyValueStore
 
-class MethodsRouter(val methodsMap: Map<String, (JSONRPCRequest) -> JSONRPCResponse>) {
+class MethodsRouter(val methodsMap: Map<String, suspend (JSONRPCRequest) -> JSONRPCResponse>) {
 
-  fun handleRequest(request: JSONRPCRequest): JSONRPCResponse {
+  suspend fun handleRequest(request: JSONRPCRequest): JSONRPCResponse {
     val methodHandler = methodsMap[request.method]
     if (methodHandler == null) {
       return methodNotFound
@@ -40,9 +39,13 @@ class MethodsRouter(val methodsMap: Map<String, (JSONRPCRequest) -> JSONRPCRespo
   }
 }
 
-class MeteredHandler(private val successCounter: LongCounter, private val failCounter: LongCounter, private val delegateHandler: (JSONRPCRequest) -> JSONRPCResponse) {
+class MeteredHandler(
+  private val successCounter: LongCounter,
+  private val failCounter: LongCounter,
+  private val delegateHandler: suspend (JSONRPCRequest) -> JSONRPCResponse,
+) {
 
-  fun handleRequest(request: JSONRPCRequest): JSONRPCResponse {
+  suspend fun handleRequest(request: JSONRPCRequest): JSONRPCResponse {
     val resp = delegateHandler(request)
     val labels = Labels.of("method", request.method)
     if (resp.error != null) {
@@ -54,9 +57,12 @@ class MeteredHandler(private val successCounter: LongCounter, private val failCo
   }
 }
 
-class MethodAllowListHandler(private val allowedMethods: List<String>, private val delegateHandler: (JSONRPCRequest) -> JSONRPCResponse) {
+class MethodAllowListHandler(
+  private val allowedMethods: List<String>,
+  private val delegateHandler: suspend (JSONRPCRequest) -> JSONRPCResponse,
+) {
 
-  fun handleRequest(request: JSONRPCRequest): JSONRPCResponse {
+  suspend fun handleRequest(request: JSONRPCRequest): JSONRPCResponse {
     var found = false
     for (method in allowedMethods) {
       if (request.method.startsWith(method)) {
@@ -71,14 +77,17 @@ class MethodAllowListHandler(private val allowedMethods: List<String>, private v
   }
 }
 
-class ThrottlingHandler(private val threshold: Int, private val delegateHandler: (JSONRPCRequest) -> JSONRPCResponse) {
+class ThrottlingHandler(
+  private val threshold: Int,
+  private val delegateHandler: suspend (JSONRPCRequest) -> JSONRPCResponse,
+) {
 
   private val limiter: SimpleLimiter<Void> = SimpleLimiter
     .newBuilder()
     .limit(FixedLimit.of(threshold))
     .build()
 
-  fun handleRequest(request: JSONRPCRequest): JSONRPCResponse {
+  suspend fun handleRequest(request: JSONRPCRequest): JSONRPCResponse {
     val listener = limiter.acquire(null)
     if (listener.isEmpty) {
       return tooManyRequests.copy(id = request.id)
@@ -95,9 +104,13 @@ class ThrottlingHandler(private val threshold: Int, private val delegateHandler:
   }
 }
 
-class CachingHandler(private val allowedMethods: List<String>, private val cacheStore: KeyValueStore<String, JSONRPCResponse>, private val delegateHandler: (JSONRPCRequest) -> JSONRPCResponse) {
+class CachingHandler(
+  private val allowedMethods: List<String>,
+  private val cacheStore: KeyValueStore<String, JSONRPCResponse>,
+  private val delegateHandler: suspend (JSONRPCRequest) -> JSONRPCResponse,
+) {
 
-  fun handleRequest(request: JSONRPCRequest): JSONRPCResponse {
+  suspend fun handleRequest(request: JSONRPCRequest): JSONRPCResponse {
     var found = false
     for (method in allowedMethods) {
       if (request.method.startsWith(method)) {
@@ -109,17 +122,15 @@ class CachingHandler(private val allowedMethods: List<String>, private val cache
       return delegateHandler(request)
     } else {
       val serializedRequest = serializeRequest(request)
-      return runBlocking {
-        var response = cacheStore.get(serializedRequest)
-        if (response == null) {
-          response = delegateHandler(request)
-          if (response.error == null) {
-            cacheStore.put(serializedRequest, response)
-          }
-          response
-        } else {
-          return@runBlocking response.copy(id = request.id)
+      val response = cacheStore.get(serializedRequest)
+      return if (response == null) {
+        val newResponse = delegateHandler(request)
+        if (newResponse.error == null) {
+          cacheStore.put(serializedRequest, newResponse)
         }
+        newResponse
+      } else {
+        response.copy(id = request.id)
       }
     }
   }
diff --git a/jsonrpc/src/main/kotlin/org/apache/tuweni/jsonrpc/methods/Web3.kt b/jsonrpc/src/main/kotlin/org/apache/tuweni/jsonrpc/methods/Web3.kt
index 5a6dd3b..218bbe7 100644
--- a/jsonrpc/src/main/kotlin/org/apache/tuweni/jsonrpc/methods/Web3.kt
+++ b/jsonrpc/src/main/kotlin/org/apache/tuweni/jsonrpc/methods/Web3.kt
@@ -22,7 +22,7 @@ import org.apache.tuweni.eth.JSONRPCRequest
 import org.apache.tuweni.eth.JSONRPCResponse
 import org.apache.tuweni.eth.invalidParams
 
-fun sha3(request: JSONRPCRequest): JSONRPCResponse {
+suspend fun sha3(request: JSONRPCRequest): JSONRPCResponse {
   if (request.params.size != 1) {
     return invalidParams.copy(id = request.id)
   }
@@ -35,7 +35,7 @@ fun sha3(request: JSONRPCRequest): JSONRPCResponse {
 }
 
 class ClientVersion(val clientId: String) {
-  fun handle(request: JSONRPCRequest): JSONRPCResponse {
+  suspend fun handle(request: JSONRPCRequest): JSONRPCResponse {
     return JSONRPCResponse(id = request.id, result = clientId)
   }
 }
diff --git a/jsonrpc/src/test/kotlin/org/apache/tuweni/jsonrpc/JSONRPCClientTest.kt b/jsonrpc/src/test/kotlin/org/apache/tuweni/jsonrpc/JSONRPCClientTest.kt
index 351a4e6..adce2b1 100644
--- a/jsonrpc/src/test/kotlin/org/apache/tuweni/jsonrpc/JSONRPCClientTest.kt
+++ b/jsonrpc/src/test/kotlin/org/apache/tuweni/jsonrpc/JSONRPCClientTest.kt
@@ -64,13 +64,13 @@ class JSONRPCClientTest {
         },
         coroutineContext = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
       )
-      server!!.start().await()
+      server!!.start()
     }
 
     @JvmStatic
     @AfterAll
     fun stopServer(): Unit = runBlocking {
-      server?.stop()?.await()
+      server?.stop()
     }
   }
 
@@ -78,7 +78,7 @@ class JSONRPCClientTest {
   fun testSendTransaction(@VertxInstance vertx: Vertx) = runBlocking {
     val keyPair =
       SECP256K1.KeyPair.fromSecretKey(SECP256K1.SecretKey.fromBytes(Bytes32.rightPad(Bytes.fromHexString("0102"))))
-    JSONRPCClient(vertx, server!!.port(), "localhost").use {
+    JSONRPCClient(vertx, "http://localhost:" + server!!.port()).use {
       val tx = Transaction(
         UInt256.ONE,
         Wei.valueOf(2),
@@ -108,7 +108,7 @@ class JSONRPCClientTest {
 
   @Test
   fun testGetBalanceToMissingClient(@VertxInstance vertx: Vertx) {
-    JSONRPCClient(vertx, 1234, "localhost").use {
+    JSONRPCClient(vertx, "http://localhost:1234").use {
       assertThrows<ConnectException> {
         runBlocking { it.getBalance_latest(Address.fromHexString("0x0102030405060708090a0b0c0d0e0f0102030405")) }
       }
diff --git a/jsonrpc/src/test/kotlin/org/apache/tuweni/jsonrpc/JSONRPCServerTest.kt b/jsonrpc/src/test/kotlin/org/apache/tuweni/jsonrpc/JSONRPCServerTest.kt
index edf5104..76f4939 100644
--- a/jsonrpc/src/test/kotlin/org/apache/tuweni/jsonrpc/JSONRPCServerTest.kt
+++ b/jsonrpc/src/test/kotlin/org/apache/tuweni/jsonrpc/JSONRPCServerTest.kt
@@ -57,14 +57,14 @@ class JSONRPCServerTest {
       },
       coroutineContext = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
     )
-    server.start().await()
+    server.start()
     try {
       val client = vertx.createHttpClient()
       val request = client.request(HttpMethod.POST, server.port(), server.networkInterface, "/").await()
       val response = request.send("{\"id\":1,\"method\":\"eth_client\",\"params\":[]}").await()
       assertEquals(200, response.statusCode())
     } finally {
-      server.stop().await()
+      server.stop()
     }
   }
 
@@ -81,7 +81,7 @@ class JSONRPCServerTest {
       basicAuthRealm = "my realm",
       coroutineContext = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
     )
-    server.start().await()
+    server.start()
     try {
       val client = vertx.createHttpClient()
       val request = client.request(HttpMethod.POST, server.port(), server.networkInterface, "/").await()
@@ -103,7 +103,7 @@ class JSONRPCServerTest {
         assertEquals(401, authedResponse.statusCode())
       }
     } finally {
-      server.stop().await()
+      server.stop()
     }
   }
 }
diff --git a/jsonrpc/src/test/kotlin/org/apache/tuweni/jsonrpc/methods/MethodsHandlerTest.kt b/jsonrpc/src/test/kotlin/org/apache/tuweni/jsonrpc/methods/MethodsHandlerTest.kt
index 69fb2a5..369a1ea 100644
--- a/jsonrpc/src/test/kotlin/org/apache/tuweni/jsonrpc/methods/MethodsHandlerTest.kt
+++ b/jsonrpc/src/test/kotlin/org/apache/tuweni/jsonrpc/methods/MethodsHandlerTest.kt
@@ -40,19 +40,19 @@ import java.util.Collections
 class MethodsHandlerTest {
 
   @Test
-  fun testMissingMethod() {
+  fun testMissingMethod() = runBlocking {
     val methodsRouter = MethodsRouter(emptyMap())
     assertEquals(methodNotFound, methodsRouter.handleRequest(JSONRPCRequest(1, "web3_sha3", arrayOf("0xdeadbeef"))))
   }
 
   @Test
-  fun testRouteMethod() {
+  fun testRouteMethod() = runBlocking {
     val methodsRouter = MethodsRouter(mapOf(Pair("web3_sha3", ::sha3)))
     assertEquals(JSONRPCResponse(1, result = "0xd4fd4e189132273036449fc9e11198c739161b4c0116a9a2dccdfa1c492006f1"), methodsRouter.handleRequest(JSONRPCRequest(1, "web3_sha3", arrayOf("0xdeadbeef"))))
   }
 
   @Test
-  fun testCountSuccess() {
+  fun testCountSuccess() = runBlocking {
     val exporter = InMemoryMetricExporter.create()
     val meterSdk = SdkMeterProvider.builder().build()
     val meter = meterSdk.get("handler")
@@ -80,7 +80,7 @@ class MethodsHandlerTest {
   }
 
   @Test
-  fun testFailMeter() {
+  fun testFailMeter() = runBlocking {
     val exporter = InMemoryMetricExporter.create()
     val meterSdk = SdkMeterProvider.builder().build()
     val meter = meterSdk.get("handler")
@@ -111,14 +111,14 @@ class MethodsHandlerTest {
 class MethodAllowListHandlerTest {
 
   @Test
-  fun testAllowedMethod() {
+  fun testAllowedMethod() = runBlocking {
     val filter = MethodAllowListHandler(listOf("eth_")) { JSONRPCResponse(1, "foo") }
     val resp = filter.handleRequest(JSONRPCRequest(1, "eth_client", emptyArray()))
     assertNull(resp.error)
   }
 
   @Test
-  fun testForbiddenMethod() {
+  fun testForbiddenMethod() = runBlocking {
     val filter = MethodAllowListHandler(listOf("eth_")) { JSONRPCResponse(1, "foo") }
     val resp = filter.handleRequest(JSONRPCRequest(1, "foo_client", emptyArray()))
     assertNotNull(resp.error)
@@ -170,7 +170,7 @@ class ThrottlingHandlerTest {
 class CachingHandlerTest {
 
   @Test
-  fun testCache() {
+  fun testCache() = runBlocking {
     val map = HashMap<String, JSONRPCResponse>()
     val kv = MapKeyValueStore.open(map)
     val handler = CachingHandler(listOf("foo"), kv) {

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@tuweni.apache.org
For additional commands, e-mail: commits-help@tuweni.apache.org