diff --git a/emerald-grpc b/emerald-grpc index f1880440..7afb478e 160000 --- a/emerald-grpc +++ b/emerald-grpc @@ -1 +1 @@ -Subproject commit f18804408ff4876db82b4106d05ac4e76b8170ef +Subproject commit 7afb478e66eb1609f03d5a7667b249e2da73932d diff --git a/src/main/kotlin/io/emeraldpay/dshackle/Global.kt b/src/main/kotlin/io/emeraldpay/dshackle/Global.kt index a9775dbb..f156558c 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/Global.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/Global.kt @@ -78,6 +78,18 @@ class Global { } } + fun getErrorValueAsIs(errorResp: ByteArray): ByteArray? { + return runCatching { + Global.objectMapper.readTree(errorResp) + ?.get("error") + ?.let { + Global.objectMapper.writeValueAsBytes(it) + } + }.getOrElse { + null + } + } + private fun isSolana(chain: Chain): Boolean { return chain == Chain.SOLANA__MAINNET || chain == Chain.SOLANA__DEVNET || chain == Chain.SOLANA__TESTNET } diff --git a/src/main/kotlin/io/emeraldpay/dshackle/rpc/NativeCall.kt b/src/main/kotlin/io/emeraldpay/dshackle/rpc/NativeCall.kt index 24bf55cb..31ba610d 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/rpc/NativeCall.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/rpc/NativeCall.kt @@ -254,6 +254,9 @@ open class NativeCall( error.data?.let { data -> result.setErrorData(data) } + if (error.errorAsIs != null) { + result.errorAsIs = ByteString.copyFrom(error.errorAsIs) + } } } else { result.payload = ByteString.copyFrom(it.result) @@ -801,6 +804,7 @@ open class NativeCall( val upstreamError: ChainCallError?, val data: String?, val upstreamSettingsData: List = emptyList(), + val errorAsIs: ByteArray? = null, ) { companion object { @@ -818,7 +822,7 @@ open class NativeCall( } fun from(t: Throwable): CallError { return when (t) { - is ChainException -> CallError(t.error.code, t.error.message, t.error, getDataAsSting(t.error.details), t.upstreamSettingsData) + is ChainException -> CallError(t.error.code, t.error.message, t.error, getDataAsSting(t.error.details), t.upstreamSettingsData, t.error.errorAsIs) is RpcException -> CallError(t.code, t.rpcMessage, null, getDataAsSting(t.details)) is CallFailure -> CallError(t.id, t.reason.message ?: "Upstream Error", null, null) else -> { @@ -833,6 +837,28 @@ open class NativeCall( } } } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is CallError) return false + + if (id != other.id) return false + if (message != other.message) return false + if (upstreamError != other.upstreamError) return false + if (data != other.data) return false + if (upstreamSettingsData != other.upstreamSettingsData) return false + + return true + } + + override fun hashCode(): Int { + var result = id + result = 31 * result + message.hashCode() + result = 31 * result + (upstreamError?.hashCode() ?: 0) + result = 31 * result + (data?.hashCode() ?: 0) + result = 31 * result + upstreamSettingsData.hashCode() + return result + } } open class CallResult @JvmOverloads constructor( diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/ChainCallError.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/ChainCallError.kt index bcca80be..1c7f180f 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/ChainCallError.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/ChainCallError.kt @@ -17,7 +17,12 @@ package io.emeraldpay.dshackle.upstream import io.emeraldpay.dshackle.upstream.ethereum.rpc.RpcException -data class ChainCallError(val code: Int, val message: String, val details: Any?) { +data class ChainCallError( + val code: Int, + val message: String, + val details: Any?, + val errorAsIs: ByteArray? = null, +) { constructor(code: Int, message: String) : this(code, message, null) @@ -39,4 +44,22 @@ data class ChainCallError(val code: Int, val message: String, val details: Any?) fun asException(id: ChainResponse.Id?, upstreamSettingsData: List): ChainException { return ChainException(id ?: ChainResponse.NumberId(-1), this, upstreamSettingsData, false) } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is ChainCallError) return false + + if (code != other.code) return false + if (message != other.message) return false + if (details != other.details) return false + + return true + } + + override fun hashCode(): Int { + var result = code + result = 31 * result + message.hashCode() + result = 31 * result + (details?.hashCode() ?: 0) + return result + } } diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/rpcclient/ResponseParser.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/rpcclient/ResponseParser.kt index b51ab438..e68f45f3 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/rpcclient/ResponseParser.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/rpcclient/ResponseParser.kt @@ -97,7 +97,8 @@ abstract class ResponseParser { state.copy(result = result) } } else if (field == "error") { - val err = readError(parser) + val errorValue = Global.getErrorValueAsIs(json) + val err = readError(parser, errorValue) if (err != null) { return state.copy(error = err) } @@ -154,6 +155,10 @@ abstract class ResponseParser { } fun readError(parser: JsonParser): ChainCallError? { + return readError(parser, null) + } + + fun readError(parser: JsonParser, errorAsIs: ByteArray?): ChainCallError? { var code = 0 var message = "" var details: Any? = null @@ -204,7 +209,7 @@ abstract class ResponseParser { } } } - return ChainCallError(code, message, details) + return ChainCallError(code, message, details, errorAsIs) } data class Preparsed( diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/rpcclient/stream/JsonRpcStreamParser.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/rpcclient/stream/JsonRpcStreamParser.kt index dd9f262f..25587a24 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/rpcclient/stream/JsonRpcStreamParser.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/rpcclient/stream/JsonRpcStreamParser.kt @@ -3,6 +3,7 @@ package io.emeraldpay.dshackle.upstream.rpcclient.stream import com.fasterxml.jackson.core.JsonFactory import com.fasterxml.jackson.core.JsonParser import com.fasterxml.jackson.core.JsonToken +import io.emeraldpay.dshackle.Global import io.emeraldpay.dshackle.upstream.ChainCallError import io.emeraldpay.dshackle.upstream.ethereum.rpc.RpcResponseError import io.emeraldpay.dshackle.upstream.rpcclient.ResponseRpcParser @@ -233,7 +234,8 @@ class JsonRpcStreamParser( return response } } else if (parser.currentName == "error") { - return SingleResponse(response?.result, responseRpcParser.readError(parser)) + val errorValue = Global.getErrorValueAsIs(firstBytes) + return SingleResponse(response?.result, responseRpcParser.readError(parser, errorValue)) } } } diff --git a/src/test/groovy/io/emeraldpay/dshackle/upstream/rpcclient/JsonRpcErrorSpec.groovy b/src/test/groovy/io/emeraldpay/dshackle/upstream/rpcclient/JsonRpcErrorSpec.groovy index 1c2a7deb..ad81f8b1 100644 --- a/src/test/groovy/io/emeraldpay/dshackle/upstream/rpcclient/JsonRpcErrorSpec.groovy +++ b/src/test/groovy/io/emeraldpay/dshackle/upstream/rpcclient/JsonRpcErrorSpec.groovy @@ -2,7 +2,6 @@ package io.emeraldpay.dshackle.upstream.rpcclient import io.emeraldpay.dshackle.upstream.ChainCallError import io.emeraldpay.dshackle.upstream.ethereum.rpc.RpcException -import nl.jqno.equalsverifier.EqualsVerifier import spock.lang.Specification class JsonRpcErrorSpec extends Specification { @@ -24,11 +23,4 @@ class JsonRpcErrorSpec extends Specification { act.message == "test test" act.details == "foo bar" } - - def "Equals"() { - when: - def v = EqualsVerifier.forClass(ChainCallError) - then: - v.verify() - } }