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