Return upstreamId in response for errors too (#254)

This commit is contained in:
KirillPamPam
2023-07-20 16:12:40 +04:00
committed by GitHub
parent 268baf0d5b
commit 121dcf0ca7
20 changed files with 112 additions and 135 deletions

View File

@@ -21,7 +21,6 @@ import io.emeraldpay.dshackle.upstream.Upstream
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcError import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcError
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcException import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcException
import io.emeraldpay.dshackle.upstream.signature.ResponseSigner import io.emeraldpay.dshackle.upstream.signature.ResponseSigner
import java.util.concurrent.ConcurrentLinkedQueue
open class AlwaysQuorum : CallQuorum { open class AlwaysQuorum : CallQuorum {
@@ -29,8 +28,7 @@ open class AlwaysQuorum : CallQuorum {
private var result: ByteArray? = null private var result: ByteArray? = null
private var rpcError: JsonRpcError? = null private var rpcError: JsonRpcError? = null
private var sig: ResponseSigner.Signature? = null private var sig: ResponseSigner.Signature? = null
private var providedUpstreamId: String? = null private val resolvers = ArrayList<Upstream>()
private val resolvers: MutableCollection<Upstream> = ConcurrentLinkedQueue()
override fun init(head: Head) { override fun init(head: Head) {
} }
@@ -47,21 +45,15 @@ open class AlwaysQuorum : CallQuorum {
return sig return sig
} }
override fun getProvidedUpstreamId(): String? {
return providedUpstreamId
}
override fun record( override fun record(
response: ByteArray, response: ByteArray,
signature: ResponseSigner.Signature?, signature: ResponseSigner.Signature?,
upstream: Upstream, upstream: Upstream
providedUpstreamId: String?
): Boolean { ): Boolean {
result = response result = response
resolved = true resolved = true
sig = signature sig = signature
resolvers.add(upstream) resolvers.add(upstream)
this.providedUpstreamId = providedUpstreamId
return true return true
} }
@@ -72,6 +64,7 @@ open class AlwaysQuorum : CallQuorum {
) { ) {
this.rpcError = error.error this.rpcError = error.error
sig = signature sig = signature
resolvers.add(upstream)
} }
override fun getResult(): ByteArray? { override fun getResult(): ByteArray? {
@@ -82,8 +75,7 @@ open class AlwaysQuorum : CallQuorum {
return rpcError return rpcError
} }
override fun getResolvedBy(): List<Upstream> = override fun getResolvedBy(): List<Upstream> = resolvers
resolvers.toList()
override fun toString(): String { override fun toString(): String {
return "Quorum: Accept Any" return "Quorum: Accept Any"

View File

@@ -28,7 +28,6 @@ open class BroadcastQuorum(
private var txid: String? = null private var txid: String? = null
private var calls = 0 private var calls = 0
private var sig: ResponseSigner.Signature? = null private var sig: ResponseSigner.Signature? = null
private var providedUpstreamId: String? = null
override fun init(head: Head) { override fun init(head: Head) {
} }
@@ -49,23 +48,17 @@ open class BroadcastQuorum(
return sig return sig
} }
override fun getProvidedUpstreamId(): String? {
return providedUpstreamId
}
override fun recordValue( override fun recordValue(
response: ByteArray, response: ByteArray,
responseValue: String?, responseValue: String?,
signature: ResponseSigner.Signature?, signature: ResponseSigner.Signature?,
upstream: Upstream, upstream: Upstream
providedUpstreamId: String?
) { ) {
calls++ calls++
if (txid == null && responseValue != null) { if (txid == null && responseValue != null) {
txid = responseValue txid = responseValue
sig = signature sig = signature
result = response result = response
this.providedUpstreamId = providedUpstreamId
} }
} }
@@ -73,16 +66,15 @@ open class BroadcastQuorum(
response: ByteArray?, response: ByteArray?,
errorMessage: String?, errorMessage: String?,
signature: ResponseSigner.Signature?, signature: ResponseSigner.Signature?,
upstream: Upstream, upstream: Upstream
providedUpstreamId: String?
) { ) {
// can be "message: known transaction: TXID", "Transaction with the same hash was already imported" or "message: Nonce too low" // can be "message: known transaction: TXID", "Transaction with the same hash was already imported" or "message: Nonce too low"
calls++ calls++
if (result == null) { if (result == null) {
result = response result = response
sig = signature sig = signature
this.providedUpstreamId = providedUpstreamId
} }
resolvers.add(upstream)
} }
override fun toString(): String { override fun toString(): String {

View File

@@ -32,9 +32,9 @@ interface CallQuorum {
fun record( fun record(
response: ByteArray, response: ByteArray,
signature: ResponseSigner.Signature?, signature: ResponseSigner.Signature?,
upstream: Upstream, upstream: Upstream
providedUpstreamId: String?
): Boolean ): Boolean
fun record( fun record(
error: JsonRpcException, error: JsonRpcException,
signature: ResponseSigner.Signature?, signature: ResponseSigner.Signature?,
@@ -42,7 +42,6 @@ interface CallQuorum {
) )
fun getSignature(): ResponseSigner.Signature? fun getSignature(): ResponseSigner.Signature?
fun getProvidedUpstreamId(): String?
fun getResult(): ByteArray? fun getResult(): ByteArray?
fun getError(): JsonRpcError? fun getError(): JsonRpcError?
fun getResolvedBy(): Collection<Upstream> fun getResolvedBy(): Collection<Upstream>

View File

@@ -21,7 +21,6 @@ import io.emeraldpay.dshackle.upstream.Upstream
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcError import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcError
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcException import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcException
import io.emeraldpay.dshackle.upstream.signature.ResponseSigner import io.emeraldpay.dshackle.upstream.signature.ResponseSigner
import java.util.concurrent.ConcurrentLinkedQueue
import java.util.concurrent.atomic.AtomicReference import java.util.concurrent.atomic.AtomicReference
/** /**
@@ -35,8 +34,7 @@ class NotLaggingQuorum(val maxLag: Long = 0) : CallQuorum {
private val failed = AtomicReference(false) private val failed = AtomicReference(false)
private var rpcError: JsonRpcError? = null private var rpcError: JsonRpcError? = null
private var sig: ResponseSigner.Signature? = null private var sig: ResponseSigner.Signature? = null
private val resolvers: MutableCollection<Upstream> = ConcurrentLinkedQueue() private val resolvers = ArrayList<Upstream>()
private var providedUpstreamId: String? = null
override fun init(head: Head) { override fun init(head: Head) {
} }
@@ -52,14 +50,12 @@ class NotLaggingQuorum(val maxLag: Long = 0) : CallQuorum {
override fun record( override fun record(
response: ByteArray, response: ByteArray,
signature: ResponseSigner.Signature?, signature: ResponseSigner.Signature?,
upstream: Upstream, upstream: Upstream
providedUpstreamId: String?
): Boolean { ): Boolean {
val lagging = upstream.getLag()?.run { this > maxLag } ?: true val lagging = upstream.getLag()?.run { this > maxLag } ?: true
if (!lagging) { if (!lagging) {
result.set(response) result.set(response)
sig = signature sig = signature
this.providedUpstreamId = providedUpstreamId
resolvers.add(upstream) resolvers.add(upstream)
return true return true
} }
@@ -76,16 +72,13 @@ class NotLaggingQuorum(val maxLag: Long = 0) : CallQuorum {
if (!lagging && result.get() == null) { if (!lagging && result.get() == null) {
failed.set(true) failed.set(true)
} }
resolvers.add(upstream)
} }
override fun getSignature(): ResponseSigner.Signature? { override fun getSignature(): ResponseSigner.Signature? {
return sig return sig
} }
override fun getProvidedUpstreamId(): String? {
return providedUpstreamId
}
override fun getResult(): ByteArray { override fun getResult(): ByteArray {
return result.get() return result.get()
} }
@@ -94,8 +87,8 @@ class NotLaggingQuorum(val maxLag: Long = 0) : CallQuorum {
return rpcError return rpcError
} }
override fun getResolvedBy(): Collection<Upstream> = override fun getResolvedBy(): Collection<Upstream> = resolvers
resolvers.toList()
override fun toString(): String { override fun toString(): String {
return "Quorum: late <= $maxLag blocks" return "Quorum: late <= $maxLag blocks"
} }

View File

@@ -9,7 +9,6 @@ import io.emeraldpay.dshackle.upstream.signature.ResponseSigner
class NotNullQuorum : CallQuorum { class NotNullQuorum : CallQuorum {
private var sig: ResponseSigner.Signature? = null private var sig: ResponseSigner.Signature? = null
private var providedUpstreamId: String? = null
private var result: ByteArray? = null private var result: ByteArray? = null
private var rpcError: JsonRpcError? = null private var rpcError: JsonRpcError? = null
private val resolvers = ArrayList<Upstream>() private val resolvers = ArrayList<Upstream>()
@@ -26,8 +25,7 @@ class NotNullQuorum : CallQuorum {
override fun record( override fun record(
response: ByteArray, response: ByteArray,
signature: ResponseSigner.Signature?, signature: ResponseSigner.Signature?,
upstream: Upstream, upstream: Upstream
providedUpstreamId: String?
): Boolean { ): Boolean {
allFailed = false allFailed = false
val receivedNull = response.isEmpty() || Global.nullValue.contentEquals(response) val receivedNull = response.isEmpty() || Global.nullValue.contentEquals(response)
@@ -35,7 +33,6 @@ class NotNullQuorum : CallQuorum {
if (seenUpstreams.contains(upId) || !receivedNull) { if (seenUpstreams.contains(upId) || !receivedNull) {
sig = signature sig = signature
result = response result = response
this.providedUpstreamId = providedUpstreamId
resolvers.add(upstream) resolvers.add(upstream)
return true return true
} }
@@ -50,22 +47,20 @@ class NotNullQuorum : CallQuorum {
rpcError = error.error rpcError = error.error
} else { } else {
result = Global.nullValue result = Global.nullValue
resolvers.add(upstream)
} }
sig = signature sig = signature
} }
resolvers.add(upstream)
seenUpstreams.add(upId) seenUpstreams.add(upId)
} }
override fun getSignature(): ResponseSigner.Signature? = sig override fun getSignature(): ResponseSigner.Signature? = sig
override fun getProvidedUpstreamId(): String? = providedUpstreamId
override fun getResult(): ByteArray? = result override fun getResult(): ByteArray? = result
override fun getError(): JsonRpcError? = rpcError override fun getError(): JsonRpcError? = rpcError
override fun getResolvedBy(): Collection<Upstream> = resolvers.toList() override fun getResolvedBy(): Collection<Upstream> = resolvers
override fun toString(): String { override fun toString(): String {
return "Quorum: Not null" return "Quorum: Not null"

View File

@@ -33,8 +33,8 @@ import org.slf4j.LoggerFactory
import org.springframework.cloud.sleuth.Tracer import org.springframework.cloud.sleuth.Tracer
import reactor.core.publisher.Flux import reactor.core.publisher.Flux
import reactor.core.publisher.Mono import reactor.core.publisher.Mono
import reactor.util.function.Tuple2
import reactor.util.function.Tuple3 import reactor.util.function.Tuple3
import reactor.util.function.Tuple4
import reactor.util.function.Tuples import reactor.util.function.Tuples
import java.util.Optional import java.util.Optional
import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicInteger
@@ -99,8 +99,8 @@ class QuorumRpcReader(
} }
private fun execute(key: JsonRpcRequest, retrySpec: reactor.util.retry.Retry): Function<Flux<Upstream>, Mono<CallQuorum>> { private fun execute(key: JsonRpcRequest, retrySpec: reactor.util.retry.Retry): Function<Flux<Upstream>, Mono<CallQuorum>> {
val quorumReduce = BiFunction<CallQuorum, Tuple4<ByteArray, Optional<ResponseSigner.Signature>, Upstream, Optional<String>>, CallQuorum> { res, a -> val quorumReduce = BiFunction<CallQuorum, Tuple3<ByteArray, Optional<ResponseSigner.Signature>, Upstream>, CallQuorum> { res, a ->
if (res.record(a.t1, a.t2.orElse(null), a.t3, a.t4.orElse(null))) { if (res.record(a.t1, a.t2.orElse(null), a.t3)) {
log.trace("Quorum is resolved for method ${key.method}") log.trace("Quorum is resolved for method ${key.method}")
apiControl.resolve() apiControl.resolve()
} else { } else {
@@ -131,13 +131,13 @@ class QuorumRpcReader(
.filter { it.isResolved() } // return nothing if not resolved .filter { it.isResolved() } // return nothing if not resolved
.map { quorum -> .map { quorum ->
// TODO find actual quorum number // TODO find actual quorum number
Result(quorum.getResult()!!, quorum.getSignature(), 1, quorum.getResolvedBy(), quorum.getProvidedUpstreamId()) Result(quorum.getResult()!!, quorum.getSignature(), 1, resolvedBy())
} }
.switchIfEmpty(defaultResult) .switchIfEmpty(defaultResult)
} }
} }
private fun callApi(api: Upstream, key: JsonRpcRequest): Mono<Tuple4<ByteArray, Optional<ResponseSigner.Signature>, Upstream, Optional<String>>> { private fun callApi(api: Upstream, key: JsonRpcRequest): Mono<Tuple3<ByteArray, Optional<ResponseSigner.Signature>, Upstream>> {
val apiReader = api.getIngressReader() val apiReader = api.getIngressReader()
val spanParams = mapOf( val spanParams = mapOf(
SPAN_REQUEST_API_TYPE to apiReader.javaClass.name, SPAN_REQUEST_API_TYPE to apiReader.javaClass.name,
@@ -152,10 +152,10 @@ class QuorumRpcReader(
} }
// must catch not only the processing of a response but also errors thrown from the .read() call // must catch not only the processing of a response but also errors thrown from the .read() call
.transform(withErrorResume(api, key)) .transform(withErrorResume(api, key))
.map { Tuples.of(it.t1, it.t2, api, it.t3) } .map { Tuples.of(it.t1, it.t2, api) }
} }
private fun withSignatureAndUpstream(api: Upstream, key: JsonRpcRequest, response: JsonRpcResponse): Function<Mono<ByteArray>, Mono<Tuple3<ByteArray, Optional<ResponseSigner.Signature>, Optional<String>>>> { private fun withSignatureAndUpstream(api: Upstream, key: JsonRpcRequest, response: JsonRpcResponse): Function<Mono<ByteArray>, Mono<Tuple2<ByteArray, Optional<ResponseSigner.Signature>>>> {
return Function { src -> return Function { src ->
src.map { src.map {
val signature = response.providedSignature val signature = response.providedSignature
@@ -164,7 +164,7 @@ class QuorumRpcReader(
} else { } else {
null null
} }
Tuples.of(it, Optional.ofNullable(signature), Optional.ofNullable(response.providedUpstreamId)) Tuples.of(it, Optional.ofNullable(signature))
} }
} }
} }
@@ -201,8 +201,9 @@ class QuorumRpcReader(
private fun setupDefaultResult(key: JsonRpcRequest): Mono<Result> { private fun setupDefaultResult(key: JsonRpcRequest): Mono<Result> {
return Mono.just(quorum).flatMap { q -> return Mono.just(quorum).flatMap { q ->
if (q.isFailed()) { if (q.isFailed()) {
val err = q.getError()?.asException(JsonRpcResponse.NumberId(key.id)) val resolvedBy = resolvedBy()?.getId()
?: JsonRpcException(JsonRpcResponse.NumberId(key.id), JsonRpcError(-32603, "Unhandled Upstream error")) val err = q.getError()?.asException(JsonRpcResponse.NumberId(key.id), resolvedBy)
?: JsonRpcException(JsonRpcResponse.NumberId(key.id), JsonRpcError(-32603, "Unhandled Upstream error"), resolvedBy)
log.warn("Quorum is failed. Method ${key.method}, message ${err.message}") log.warn("Quorum is failed. Method ${key.method}, message ${err.message}")
Mono.error(err) Mono.error(err)
} else { } else {
@@ -212,13 +213,16 @@ class QuorumRpcReader(
} }
} }
private fun resolvedBy() =
if (quorum.getResolvedBy().isEmpty()) null else quorum.getResolvedBy().last()
private fun noResponse(method: String, q: CallQuorum): Mono<Result> { private fun noResponse(method: String, q: CallQuorum): Mono<Result> {
return apiControl.upstreamsMatchesResponse()?.run { return apiControl.upstreamsMatchesResponse()?.run {
tracer.currentSpan()?.tag(SPAN_NO_RESPONSE_MESSAGE, getFullCause()) tracer.currentSpan()?.tag(SPAN_NO_RESPONSE_MESSAGE, getFullCause())
val cause = getCause(method) ?: return Mono.empty() val cause = getCause(method) ?: return Mono.empty()
if (cause.shouldReturnNull) { if (cause.shouldReturnNull) {
Mono.just( Mono.just(
Result(Global.nullValue, null, 1, emptyList(), null) Result(Global.nullValue, null, 1, null)
) )
} else { } else {
Mono.error(RpcException(1, "No response for method $method. Cause - ${cause.cause}")) Mono.error(RpcException(1, "No response for method $method. Cause - ${cause.cause}"))
@@ -230,7 +234,6 @@ class QuorumRpcReader(
val value: ByteArray, val value: ByteArray,
val signature: ResponseSigner.Signature?, val signature: ResponseSigner.Signature?,
val quorum: Int, val quorum: Int,
val resolvers: Collection<Upstream>, val resolvedBy: Upstream?
val providedUpstreamId: String?
) )
} }

View File

@@ -23,7 +23,6 @@ import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcException
import io.emeraldpay.dshackle.upstream.signature.ResponseSigner import io.emeraldpay.dshackle.upstream.signature.ResponseSigner
import io.emeraldpay.etherjar.rpc.RpcException import io.emeraldpay.etherjar.rpc.RpcException
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.util.concurrent.ConcurrentLinkedQueue
abstract class ValueAwareQuorum<T>( abstract class ValueAwareQuorum<T>(
val clazz: Class<T> val clazz: Class<T>
@@ -31,7 +30,7 @@ abstract class ValueAwareQuorum<T>(
private val log = LoggerFactory.getLogger(ValueAwareQuorum::class.java) private val log = LoggerFactory.getLogger(ValueAwareQuorum::class.java)
private var rpcError: JsonRpcError? = null private var rpcError: JsonRpcError? = null
private val resolvers: MutableCollection<Upstream> = ConcurrentLinkedQueue() protected val resolvers = ArrayList<Upstream>()
fun extractValue(response: ByteArray, clazz: Class<T>): T? { fun extractValue(response: ByteArray, clazz: Class<T>): T? {
return Global.objectMapper.readValue(response.inputStream(), clazz) return Global.objectMapper.readValue(response.inputStream(), clazz)
@@ -40,17 +39,16 @@ abstract class ValueAwareQuorum<T>(
override fun record( override fun record(
response: ByteArray, response: ByteArray,
signature: ResponseSigner.Signature?, signature: ResponseSigner.Signature?,
upstream: Upstream, upstream: Upstream
providedUpstreamId: String?
): Boolean { ): Boolean {
try { try {
val value = extractValue(response, clazz) val value = extractValue(response, clazz)
recordValue(response, value, signature, upstream, providedUpstreamId) recordValue(response, value, signature, upstream)
resolvers.add(upstream) resolvers.add(upstream)
} catch (e: RpcException) { } catch (e: RpcException) {
recordError(response, e.rpcMessage, signature, upstream, providedUpstreamId) recordError(response, e.rpcMessage, signature, upstream)
} catch (e: Exception) { } catch (e: Exception) {
recordError(response, e.message, signature, upstream, providedUpstreamId) recordError(response, e.message, signature, upstream)
} }
return isResolved() return isResolved()
} }
@@ -61,29 +59,26 @@ abstract class ValueAwareQuorum<T>(
upstream: Upstream upstream: Upstream
) { ) {
this.rpcError = error.error this.rpcError = error.error
recordError(null, error.error.message, signature, upstream, null) recordError(null, error.error.message, signature, upstream)
} }
abstract fun recordValue( abstract fun recordValue(
response: ByteArray, response: ByteArray,
responseValue: T?, responseValue: T?,
signature: ResponseSigner.Signature?, signature: ResponseSigner.Signature?,
upstream: Upstream, upstream: Upstream
providedUpstreamId: String?
) )
abstract fun recordError( abstract fun recordError(
response: ByteArray?, response: ByteArray?,
errorMessage: String?, errorMessage: String?,
signature: ResponseSigner.Signature?, signature: ResponseSigner.Signature?,
upstream: Upstream, upstream: Upstream
providedUpstreamId: String?
) )
override fun getError(): JsonRpcError? { override fun getError(): JsonRpcError? {
return rpcError return rpcError
} }
override fun getResolvedBy(): Collection<Upstream> = override fun getResolvedBy(): Collection<Upstream> = resolvers
resolvers.toList()
} }

View File

@@ -28,7 +28,6 @@ import io.emeraldpay.dshackle.commons.LOCAL_READER
import io.emeraldpay.dshackle.commons.REMOTE_QUORUM_RPC_READER import io.emeraldpay.dshackle.commons.REMOTE_QUORUM_RPC_READER
import io.emeraldpay.dshackle.commons.SPAN_ERROR import io.emeraldpay.dshackle.commons.SPAN_ERROR
import io.emeraldpay.dshackle.commons.SPAN_REQUEST_ID import io.emeraldpay.dshackle.commons.SPAN_REQUEST_ID
import io.emeraldpay.dshackle.commons.SPAN_RESPONSE_UPSTREAM_ID
import io.emeraldpay.dshackle.commons.SPAN_STATUS_MESSAGE import io.emeraldpay.dshackle.commons.SPAN_STATUS_MESSAGE
import io.emeraldpay.dshackle.config.MainConfig import io.emeraldpay.dshackle.config.MainConfig
import io.emeraldpay.dshackle.quorum.CallQuorum import io.emeraldpay.dshackle.quorum.CallQuorum
@@ -131,9 +130,6 @@ open class NativeCall(
private fun completeSpan(callResult: CallResult, requestCount: Int) { private fun completeSpan(callResult: CallResult, requestCount: Int) {
val span = tracer.currentSpan() val span = tracer.currentSpan()
callResult.upstreamId?.let {
span?.tag(SPAN_RESPONSE_UPSTREAM_ID, it)
}
if (callResult.isError()) { if (callResult.isError()) {
errorSpan(span, callResult.error?.message ?: "Internal error") errorSpan(span, callResult.error?.message ?: "Internal error")
} }
@@ -403,9 +399,7 @@ open class NativeCall(
.map { .map {
val bytes = ctx.resultDecorator.processResult(it) val bytes = ctx.resultDecorator.processResult(it)
validateResult(bytes, "remote", ctx) validateResult(bytes, "remote", ctx)
val upId = it.providedUpstreamId CallResult.ok(ctx.id, ctx.nonce, bytes, it.signature, it.resolvedBy?.getId(), ctx)
?: if (it.resolvers.isEmpty()) ctx.upstream.getId() else it.resolvers.first().getId()
CallResult.ok(ctx.id, ctx.nonce, bytes, it.signature, upId, ctx)
} }
.onErrorResume { t -> .onErrorResume { t ->
Mono.just(CallResult.fail(ctx.id, ctx.nonce, t, ctx)) Mono.just(CallResult.fail(ctx.id, ctx.nonce, t, ctx))
@@ -490,10 +484,8 @@ open class NativeCall(
} }
override fun processResult(result: QuorumRpcReader.Result): ByteArray { override fun processResult(result: QuorumRpcReader.Result): ByteArray {
val bytes = result.value val bytes = result.value
if (bytes.last() == quoteCode) { if (bytes.last() == quoteCode && result.resolvedBy != null) {
val suffix = result.resolvers val suffix = result.resolvedBy.nodeId()
.map { it.nodeId() }
.first()
.toUByte() .toUByte()
.toString(16).padStart(2, padChar = '0').toByteArray() .toString(16).padStart(2, padChar = '0').toByteArray()
bytes[bytes.lastIndex] = suffix.first() bytes[bytes.lastIndex] = suffix.first()
@@ -598,7 +590,13 @@ open class NativeCall(
open class CallFailure(val id: Int, val reason: Throwable) : Exception("Failed to call $id: ${reason.message}") open class CallFailure(val id: Int, val reason: Throwable) : Exception("Failed to call $id: ${reason.message}")
open class CallError(val id: Int, val message: String, val upstreamError: JsonRpcError?, val data: String?) { open class CallError(
val id: Int,
val message: String,
val upstreamError: JsonRpcError?,
val data: String?,
val upstreamId: String? = null
) {
companion object { companion object {
@@ -615,7 +613,7 @@ open class NativeCall(
} }
fun from(t: Throwable): CallError { fun from(t: Throwable): CallError {
return when (t) { return when (t) {
is JsonRpcException -> CallError(t.error.code, t.error.message, t.error, getDataAsSting(t.error.details)) is JsonRpcException -> CallError(t.error.code, t.error.message, t.error, getDataAsSting(t.error.details), t.upstreamId)
is RpcException -> CallError(t.code, t.rpcMessage, null, getDataAsSting(t.details)) is RpcException -> CallError(t.code, t.rpcMessage, null, getDataAsSting(t.details))
is CallFailure -> CallError(t.id, t.reason.message ?: "Upstream Error", null, null) is CallFailure -> CallError(t.id, t.reason.message ?: "Upstream Error", null, null)
else -> { else -> {
@@ -641,6 +639,16 @@ open class NativeCall(
val upstreamId: String?, val upstreamId: String?,
val ctx: ValidCallContext<ParsedCallDetails>? val ctx: ValidCallContext<ParsedCallDetails>?
) { ) {
constructor(
id: Int,
nonce: Long?,
result: ByteArray?,
callError: CallError?,
signature: ResponseSigner.Signature?,
ctx: ValidCallContext<ParsedCallDetails>?
) : this(id, nonce, result, callError, signature, callError?.upstreamId, ctx)
companion object { companion object {
fun ok(id: Int, nonce: Long?, result: ByteArray, signature: ResponseSigner.Signature?, upstreamId: String?, ctx: ValidCallContext<ParsedCallDetails>?): CallResult { fun ok(id: Int, nonce: Long?, result: ByteArray, signature: ResponseSigner.Signature?, upstreamId: String?, ctx: ValidCallContext<ParsedCallDetails>?): CallResult {
return CallResult(id, nonce, result, null, signature, upstreamId, ctx) return CallResult(id, nonce, result, null, signature, upstreamId, ctx)
@@ -651,7 +659,7 @@ open class NativeCall(
} }
fun fail(id: Int, nonce: Long?, error: Throwable, ctx: ValidCallContext<ParsedCallDetails>?): CallResult { fun fail(id: Int, nonce: Long?, error: Throwable, ctx: ValidCallContext<ParsedCallDetails>?): CallResult {
return CallResult(id, nonce, null, CallError.from(error), null, null, ctx) return CallResult(id, nonce, null, CallError.from(error), null, ctx)
} }
} }

View File

@@ -377,6 +377,7 @@ open class WsConnectionImpl(
RpcResponseError.CODE_INTERNAL_ERROR, RpcResponseError.CODE_INTERNAL_ERROR,
"Response not received from WebSocket" "Response not received from WebSocket"
), ),
null,
false false
) )

View File

@@ -31,6 +31,10 @@ data class JsonRpcError(val code: Int, val message: String, val details: Any?) {
} }
fun asException(id: JsonRpcResponse.Id?): JsonRpcException { fun asException(id: JsonRpcResponse.Id?): JsonRpcException {
return JsonRpcException(id ?: JsonRpcResponse.NumberId(-1), this, false) return JsonRpcException(id ?: JsonRpcResponse.NumberId(-1), this, null, false)
}
fun asException(id: JsonRpcResponse.Id?, upstreamId: String?): JsonRpcException {
return JsonRpcException(id ?: JsonRpcResponse.NumberId(-1), this, upstreamId, false)
} }
} }

View File

@@ -20,6 +20,7 @@ import io.emeraldpay.etherjar.rpc.RpcException
class JsonRpcException( class JsonRpcException(
val id: JsonRpcResponse.Id, val id: JsonRpcResponse.Id,
val error: JsonRpcError, val error: JsonRpcError,
val upstreamId: String? = null,
writableStackTrace: Boolean = true writableStackTrace: Boolean = true
) : Exception(error.message, null, true, writableStackTrace) { ) : Exception(error.message, null, true, writableStackTrace) {

View File

@@ -131,7 +131,7 @@ class JsonRpcHttpClient(
return Function { resp -> return Function { resp ->
resp.flatMap { resp.flatMap {
if (it.hasError()) { if (it.hasError()) {
Mono.error(JsonRpcException(it.id, it.error!!, false)) Mono.error(JsonRpcException(it.id, it.error!!, null, false))
} else { } else {
Mono.just(it) Mono.just(it)
} }

View File

@@ -98,7 +98,7 @@ class WriteRpcJsonSpec extends Specification {
def call = new ProxyCall(ProxyCall.RpcType.SINGLE) def call = new ProxyCall(ProxyCall.RpcType.SINGLE)
call.ids[1] = 1 call.ids[1] = 1
def data = [ def data = [
new NativeCall.CallResult(1, null, null, new NativeCall.CallError(1, "Internal Error", null, null), null, null, null) new NativeCall.CallResult(1, null, null, new NativeCall.CallError(1, "Internal Error", null, null, null), null, null, null)
] ]
when: when:
def act = writer.toJson(call, data[0]) def act = writer.toJson(call, data[0])
@@ -127,7 +127,7 @@ class WriteRpcJsonSpec extends Specification {
call.ids[3] = 15 call.ids[3] = 15
def data = [ def data = [
new NativeCall.CallResult(1, null, '"0x98dbb1"'.bytes, null, null, null, null), new NativeCall.CallResult(1, null, '"0x98dbb1"'.bytes, null, null, null, null),
new NativeCall.CallResult(2, null, null, new NativeCall.CallError(2, "oops", null, null), null, null, null), new NativeCall.CallResult(2, null, null, new NativeCall.CallError(2, "oops", null, null, null), null, null, null),
new NativeCall.CallResult(3, null, '{"hash": "0x2484f459dc"}'.bytes, null, null, null, null), new NativeCall.CallResult(3, null, '{"hash": "0x2484f459dc"}'.bytes, null, null, null, null),
] ]
when: when:

View File

@@ -42,7 +42,7 @@ class AlwaysQuorumSpec extends Specification {
def quorum = new AlwaysQuorum() def quorum = new AlwaysQuorum()
def up = Stub(Upstream) def up = Stub(Upstream)
when: when:
quorum.record("123".bytes, new ResponseSigner.Signature("sig1".bytes, "test", 100), up, null) quorum.record("123".bytes, new ResponseSigner.Signature("sig1".bytes, "test", 100), up)
then: then:
quorum.isResolved() quorum.isResolved()
quorum.getResult() == "123".bytes quorum.getResult() == "123".bytes

View File

@@ -40,21 +40,21 @@ class BroadcastQuorumSpec extends Specification {
!q.isResolved() !q.isResolved()
when: when:
q.record('"0xeaa972c0d8d1ecd3e34fbbef6d34e06670e745c788bdba31c4234a1762f0378c"'.bytes, null, upstream1, null) q.record('"0xeaa972c0d8d1ecd3e34fbbef6d34e06670e745c788bdba31c4234a1762f0378c"'.bytes, null, upstream1)
then: then:
!q.isResolved() !q.isResolved()
1 * q.recordValue(_, "0xeaa972c0d8d1ecd3e34fbbef6d34e06670e745c788bdba31c4234a1762f0378c", _, _, _) 1 * q.recordValue(_, "0xeaa972c0d8d1ecd3e34fbbef6d34e06670e745c788bdba31c4234a1762f0378c", _, _)
when: when:
q.record('"0xeaa972c0d8d1ecd3e34fbbef6d34e06670e745c788bdba31c4234a1762f0378c"'.bytes, null, upstream2, null) q.record('"0xeaa972c0d8d1ecd3e34fbbef6d34e06670e745c788bdba31c4234a1762f0378c"'.bytes, null, upstream2)
then: then:
!q.isResolved() !q.isResolved()
1 * q.recordValue(_, "0xeaa972c0d8d1ecd3e34fbbef6d34e06670e745c788bdba31c4234a1762f0378c", _, _, _) 1 * q.recordValue(_, "0xeaa972c0d8d1ecd3e34fbbef6d34e06670e745c788bdba31c4234a1762f0378c", _, _)
when: when:
q.record(new JsonRpcException(1, "Nonce too low"), null, upstream3) q.record(new JsonRpcException(1, "Nonce too low"), null, upstream3)
then: then:
1 * q.recordError(_, _, _, _, _) 1 * q.recordError(_, _, _, _)
q.isResolved() q.isResolved()
objectMapper.readValue(q.result, Object) == "0xeaa972c0d8d1ecd3e34fbbef6d34e06670e745c788bdba31c4234a1762f0378c" objectMapper.readValue(q.result, Object) == "0xeaa972c0d8d1ecd3e34fbbef6d34e06670e745c788bdba31c4234a1762f0378c"
} }
@@ -75,18 +75,18 @@ class BroadcastQuorumSpec extends Specification {
q.record(new JsonRpcException(1, "Internal error"), null, upstream1) q.record(new JsonRpcException(1, "Internal error"), null, upstream1)
then: then:
!q.isResolved() !q.isResolved()
1 * q.recordError(_, _, _, _, _) 1 * q.recordError(_, _, _, _)
when: when:
q.record('"0xeaa972c0d8d1ecd3e34fbbef6d34e06670e745c788bdba31c4234a1762f0378c"'.bytes, null, upstream2, null) q.record('"0xeaa972c0d8d1ecd3e34fbbef6d34e06670e745c788bdba31c4234a1762f0378c"'.bytes, null, upstream2)
then: then:
!q.isResolved() !q.isResolved()
1 * q.recordValue(_, "0xeaa972c0d8d1ecd3e34fbbef6d34e06670e745c788bdba31c4234a1762f0378c", _, _, _) 1 * q.recordValue(_, "0xeaa972c0d8d1ecd3e34fbbef6d34e06670e745c788bdba31c4234a1762f0378c", _, _)
when: when:
q.record(new JsonRpcException(1, "Nonce too low"), null, upstream3) q.record(new JsonRpcException(1, "Nonce too low"), null, upstream3)
then: then:
1 * q.recordError(_, _, _, _, _) 1 * q.recordError(_, _, _, _)
q.isResolved() q.isResolved()
objectMapper.readValue(q.result, Object) == "0xeaa972c0d8d1ecd3e34fbbef6d34e06670e745c788bdba31c4234a1762f0378c" objectMapper.readValue(q.result, Object) == "0xeaa972c0d8d1ecd3e34fbbef6d34e06670e745c788bdba31c4234a1762f0378c"
} }

View File

@@ -30,7 +30,7 @@ class NotLaggingQuorumSpec extends Specification {
def quorum = new NotLaggingQuorum(1) def quorum = new NotLaggingQuorum(1)
when: when:
quorum.record(value, null, up, null) quorum.record(value, null, up)
then: then:
1 * up.getLag() >> 0 1 * up.getLag() >> 0
quorum.isResolved() quorum.isResolved()
@@ -45,14 +45,13 @@ class NotLaggingQuorumSpec extends Specification {
def quorum = new NotLaggingQuorum(1) def quorum = new NotLaggingQuorum(1)
when: when:
quorum.record(value, new ResponseSigner.Signature("sig1".bytes, "test", 100), up, "test") quorum.record(value, new ResponseSigner.Signature("sig1".bytes, "test", 100), up)
then: then:
1 * up.getLag() >> 0 1 * up.getLag() >> 0
quorum.isResolved() quorum.isResolved()
!quorum.isFailed() !quorum.isFailed()
quorum.result == value quorum.result == value
quorum.signature == new ResponseSigner.Signature("sig1".bytes, "test", 100) quorum.signature == new ResponseSigner.Signature("sig1".bytes, "test", 100)
quorum.providedUpstreamId == "test"
} }
def "Resolves if ok lag"() { def "Resolves if ok lag"() {
@@ -62,7 +61,7 @@ class NotLaggingQuorumSpec extends Specification {
def quorum = new NotLaggingQuorum(1) def quorum = new NotLaggingQuorum(1)
when: when:
quorum.record(value, null, up, null) quorum.record(value, null, up)
then: then:
1 * up.getLag() >> 1 1 * up.getLag() >> 1
quorum.isResolved() quorum.isResolved()
@@ -77,7 +76,7 @@ class NotLaggingQuorumSpec extends Specification {
def quorum = new NotLaggingQuorum(1) def quorum = new NotLaggingQuorum(1)
when: when:
quorum.record(value, null, up, null) quorum.record(value, null, up)
then: then:
1 * up.getLag() >> 2 1 * up.getLag() >> 2
!quorum.isResolved() !quorum.isResolved()

View File

@@ -22,10 +22,10 @@ class NotNullQuorumSpec extends Specification {
def quorum = new NotNullQuorum() def quorum = new NotNullQuorum()
when: when:
def res = quorum.record(value, new ResponseSigner.Signature("sig1".bytes, "test", 100), up, "id") def res = quorum.record(value, new ResponseSigner.Signature("sig1".bytes, "test", 100), up)
def res1 = quorum.record(value, new ResponseSigner.Signature("sig1".bytes, "test", 100), up1, "id1") def res1 = quorum.record(value, new ResponseSigner.Signature("sig1".bytes, "test", 100), up1)
def res2 = quorum.record(value, new ResponseSigner.Signature("sig1".bytes, "test", 100), up2, "id2") def res2 = quorum.record(value, new ResponseSigner.Signature("sig1".bytes, "test", 100), up2)
def res3 = quorum.record(value, new ResponseSigner.Signature("sig1".bytes, "test", 100), up, "id") def res3 = quorum.record(value, new ResponseSigner.Signature("sig1".bytes, "test", 100), up)
then: then:
!res !res
!res1 !res1
@@ -35,7 +35,6 @@ class NotNullQuorumSpec extends Specification {
!quorum.isFailed() !quorum.isFailed()
quorum.isResolved() quorum.isResolved()
quorum.signature == new ResponseSigner.Signature("sig1".bytes, "test", 100) quorum.signature == new ResponseSigner.Signature("sig1".bytes, "test", 100)
quorum.providedUpstreamId == "id"
} }
def "Failed if all upstreams respond with error"() { def "Failed if all upstreams respond with error"() {
@@ -78,7 +77,7 @@ class NotNullQuorumSpec extends Specification {
def quorum = new NotNullQuorum() def quorum = new NotNullQuorum()
when: when:
def res = quorum.record(value, new ResponseSigner.Signature("sig1".bytes, "test", 100), up, "id") def res = quorum.record(value, new ResponseSigner.Signature("sig1".bytes, "test", 100), up)
quorum.record(new JsonRpcException(10, "error"), new ResponseSigner.Signature("sig1".bytes, "test", 100), up1) quorum.record(new JsonRpcException(10, "error"), new ResponseSigner.Signature("sig1".bytes, "test", 100), up1)
quorum.record(new JsonRpcException(10, "error"), new ResponseSigner.Signature("sig1".bytes, "test", 100), up2) quorum.record(new JsonRpcException(10, "error"), new ResponseSigner.Signature("sig1".bytes, "test", 100), up2)
quorum.record(new JsonRpcException(10, "error"), new ResponseSigner.Signature("sig1".bytes, "test", 100), up) quorum.record(new JsonRpcException(10, "error"), new ResponseSigner.Signature("sig1".bytes, "test", 100), up)

View File

@@ -66,14 +66,14 @@ class ValueAwareQuorumSpec extends Specification {
} }
@Override @Override
void recordValue(@NotNull byte[] response, @Nullable Object responseValue, @Nullable ResponseSigner.Signature signature, @NotNull Upstream upstream, @Nullable String providedUpstreamId) { void recordValue(@NotNull byte[] response, @Nullable Object responseValue, @Nullable ResponseSigner.Signature signature, @NotNull Upstream upstream) {
} }
@Override @Override
void recordError(@Nullable byte[] response, @Nullable String errorMessage, @Nullable ResponseSigner.Signature signature, @NotNull Upstream upstream, @Nullable String providedUpstreamId) { void recordError(@Nullable byte[] response, @Nullable String errorMessage, @Nullable ResponseSigner.Signature signature, @NotNull Upstream upstream) {
} }
@@ -101,10 +101,5 @@ class ValueAwareQuorumSpec extends Specification {
boolean isFailed() { boolean isFailed() {
return false return false
} }
@Override
String getProvidedUpstreamId() {
return null
}
} }
} }

View File

@@ -134,7 +134,7 @@ class NativeCallSpec extends Specification {
def nativeCall = nativeCall() def nativeCall = nativeCall()
nativeCall.quorumReaderFactory = Mock(QuorumReaderFactory) { nativeCall.quorumReaderFactory = Mock(QuorumReaderFactory) {
1 * create(_, _, _, _) >> Mock(QuorumReader) { 1 * create(_, _, _, _) >> Mock(QuorumReader) {
1 * read(_) >> Mono.just(new QuorumRpcReader.Result("\"foo\"".bytes, null, 1, Collections.singletonList(ups), null)) 1 * read(_) >> Mono.just(new QuorumRpcReader.Result("\"foo\"".bytes, null, 1, ups))
} }
} }
def call = new NativeCall.ValidCallContext(1, 10, TestingCommons.multistream(TestingCommons.api()), Selector.empty, quorum, def call = new NativeCall.ValidCallContext(1, 10, TestingCommons.multistream(TestingCommons.api()), Selector.empty, quorum,
@@ -181,7 +181,7 @@ class NativeCallSpec extends Specification {
nativeCall.quorumReaderFactory = Mock(QuorumReaderFactory) { nativeCall.quorumReaderFactory = Mock(QuorumReaderFactory) {
1 * create(_, _, _, _) >> Mock(QuorumReader) { 1 * create(_, _, _, _) >> Mock(QuorumReader) {
1 * read(new JsonRpcRequest("eth_test", [], 10)) >> Mono.error( 1 * read(new JsonRpcRequest("eth_test", [], 10)) >> Mono.error(
new JsonRpcException(JsonRpcResponse.Id.from(12), new JsonRpcError(-32123, "Foo Bar", "Foo Bar Baz"), true) new JsonRpcException(JsonRpcResponse.Id.from(12), new JsonRpcError(-32123, "Foo Bar", "Foo Bar Baz"), null, true)
) )
} }
} }
@@ -617,7 +617,7 @@ class NativeCallSpec extends Specification {
def nativeCall = nativeCall(multistreamHolder) def nativeCall = nativeCall(multistreamHolder)
nativeCall.quorumReaderFactory = Mock(QuorumReaderFactory) { nativeCall.quorumReaderFactory = Mock(QuorumReaderFactory) {
1 * create(_, _, _, _) >> Mock(QuorumReader) { 1 * create(_, _, _, _) >> Mock(QuorumReader) {
1 * read(_) >> Mono.just(new QuorumRpcReader.Result("\"0xab\"".bytes, null, 1, Collections.singletonList(ups), null)) 1 * read(_) >> Mono.just(new QuorumRpcReader.Result("\"0xab\"".bytes, null, 1, ups))
} }
} }
def call = new NativeCall.ValidCallContext(1, 10, multistream, Selector.empty, quorum, def call = new NativeCall.ValidCallContext(1, 10, multistream, Selector.empty, quorum,
@@ -652,7 +652,7 @@ class NativeCallSpec extends Specification {
def nativeCall = nativeCall(multistreamHolder) def nativeCall = nativeCall(multistreamHolder)
nativeCall.quorumReaderFactory = Mock(QuorumReaderFactory) { nativeCall.quorumReaderFactory = Mock(QuorumReaderFactory) {
1 * create(_, _, _, _) >> Mock(QuorumReader) { 1 * create(_, _, _, _) >> Mock(QuorumReader) {
1 * read(_) >> Mono.just(new QuorumRpcReader.Result("\"0xab\"".bytes, null, 1, Collections.singletonList(ups), null)) 1 * read(_) >> Mono.just(new QuorumRpcReader.Result("\"0xab\"".bytes, null, 1, ups))
} }
} }
def call = new NativeCall.ValidCallContext(1, 10, multistream, Selector.empty, quorum, def call = new NativeCall.ValidCallContext(1, 10, multistream, Selector.empty, quorum,

View File

@@ -13,6 +13,7 @@ import io.emeraldpay.dshackle.upstream.ApiSource
import io.emeraldpay.dshackle.upstream.Head import io.emeraldpay.dshackle.upstream.Head
import io.emeraldpay.dshackle.upstream.Multistream import io.emeraldpay.dshackle.upstream.Multistream
import io.emeraldpay.dshackle.upstream.Selector import io.emeraldpay.dshackle.upstream.Selector
import io.emeraldpay.dshackle.upstream.Upstream
import io.emeraldpay.dshackle.upstream.calls.DefaultEthereumMethods import io.emeraldpay.dshackle.upstream.calls.DefaultEthereumMethods
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
import io.emeraldpay.etherjar.domain.Address import io.emeraldpay.etherjar.domain.Address
@@ -34,7 +35,7 @@ class EthereumDirectReaderSpec extends Specification {
String hash1 = "0x40d15edaff9acdabd2a1c96fd5f683b3300aad34e7015f34def3c56ba8a7ffb5" String hash1 = "0x40d15edaff9acdabd2a1c96fd5f683b3300aad34e7015f34def3c56ba8a7ffb5"
String address1 = "0xe0aadb0a012dbcdc529c4c743d3e0385a0b54d3d" String address1 = "0xe0aadb0a012dbcdc529c4c743d3e0385a0b54d3d"
List<Byte> resolvers = Collections.singletonList((byte)1) Upstream resolver = TestingCommons.upstream()
def "Reads block by hash"() { def "Reads block by hash"() {
setup: setup:
@@ -59,7 +60,7 @@ class EthereumDirectReaderSpec extends Specification {
1 * create(_, _, _, _,) >> Mock(QuorumReader) { 1 * create(_, _, _, _,) >> Mock(QuorumReader) {
1 * read(new JsonRpcRequest("eth_getBlockByHash", [hash1, false])) >> Mono.just( 1 * read(new JsonRpcRequest("eth_getBlockByHash", [hash1, false])) >> Mono.just(
new QuorumRpcReader.Result( new QuorumRpcReader.Result(
Global.objectMapper.writeValueAsBytes(json), null, 1, resolvers, null) Global.objectMapper.writeValueAsBytes(json), null, 1, resolver)
) )
} }
} }
@@ -89,7 +90,7 @@ class EthereumDirectReaderSpec extends Specification {
1 * create(_, _, _, _) >> Mock(QuorumReader) { 1 * create(_, _, _, _) >> Mock(QuorumReader) {
1 * read(new JsonRpcRequest("eth_getBlockByHash", [hash1, false])) >> Mono.just( 1 * read(new JsonRpcRequest("eth_getBlockByHash", [hash1, false])) >> Mono.just(
new QuorumRpcReader.Result( new QuorumRpcReader.Result(
Global.objectMapper.writeValueAsBytes(null), null, 1, resolvers, null Global.objectMapper.writeValueAsBytes(null), null, 1, resolver
) )
) )
} }
@@ -127,7 +128,7 @@ class EthereumDirectReaderSpec extends Specification {
1 * create(_, _, _, _) >> Mock(QuorumReader) { 1 * create(_, _, _, _) >> Mock(QuorumReader) {
1 * read(new JsonRpcRequest("eth_getBlockByNumber", ["0x64", false])) >> Mono.just( 1 * read(new JsonRpcRequest("eth_getBlockByNumber", ["0x64", false])) >> Mono.just(
new QuorumRpcReader.Result( new QuorumRpcReader.Result(
Global.objectMapper.writeValueAsBytes(json), null, 1, resolvers, null Global.objectMapper.writeValueAsBytes(json), null, 1, resolver
) )
) )
} }
@@ -163,7 +164,7 @@ class EthereumDirectReaderSpec extends Specification {
1 * create(_, _, _, _) >> Mock(QuorumReader) { 1 * create(_, _, _, _) >> Mock(QuorumReader) {
1 * read(new JsonRpcRequest("eth_getTransactionByHash", [hash1])) >> Mono.just( 1 * read(new JsonRpcRequest("eth_getTransactionByHash", [hash1])) >> Mono.just(
new QuorumRpcReader.Result( new QuorumRpcReader.Result(
Global.objectMapper.writeValueAsBytes(json), null, 1, resolvers, null Global.objectMapper.writeValueAsBytes(json), null, 1, resolver
) )
) )
} }
@@ -199,7 +200,7 @@ class EthereumDirectReaderSpec extends Specification {
1 * create(_, _, _, _) >> Mock(QuorumReader) { 1 * create(_, _, _, _) >> Mock(QuorumReader) {
1 * read(new JsonRpcRequest("eth_getTransactionReceipt", [hash1])) >> Mono.just( 1 * read(new JsonRpcRequest("eth_getTransactionReceipt", [hash1])) >> Mono.just(
new QuorumRpcReader.Result( new QuorumRpcReader.Result(
Global.objectMapper.writeValueAsBytes(json), null, 1, new ArrayList<Byte>(), null Global.objectMapper.writeValueAsBytes(json), null, 1, resolver
) )
) )
} }
@@ -236,7 +237,7 @@ class EthereumDirectReaderSpec extends Specification {
1 * create(_, _, _, _) >> Mock(QuorumReader) { 1 * create(_, _, _, _) >> Mock(QuorumReader) {
1 * read(new JsonRpcRequest("eth_getTransactionReceipt", [hash1])) >> Mono.just( 1 * read(new JsonRpcRequest("eth_getTransactionReceipt", [hash1])) >> Mono.just(
new QuorumRpcReader.Result( new QuorumRpcReader.Result(
Global.objectMapper.writeValueAsBytes(json), null, 1, new ArrayList<Byte>(), null Global.objectMapper.writeValueAsBytes(json), null, 1, resolver
) )
) )
} }
@@ -264,7 +265,7 @@ class EthereumDirectReaderSpec extends Specification {
1 * create(_, _, _, _) >> Mock(QuorumReader) { 1 * create(_, _, _, _) >> Mock(QuorumReader) {
1 * read(new JsonRpcRequest("eth_getTransactionByHash", [hash1])) >> Mono.just( 1 * read(new JsonRpcRequest("eth_getTransactionByHash", [hash1])) >> Mono.just(
new QuorumRpcReader.Result( new QuorumRpcReader.Result(
Global.objectMapper.writeValueAsBytes(null), null, 1, resolvers, null Global.objectMapper.writeValueAsBytes(null), null, 1, resolver
) )
) )
} }
@@ -295,7 +296,7 @@ class EthereumDirectReaderSpec extends Specification {
1 * create(_, _, _, _) >> Mock(QuorumReader) { 1 * create(_, _, _, _) >> Mock(QuorumReader) {
1 * read(new JsonRpcRequest("eth_getBalance", [address1, "latest"])) >> Mono.just( 1 * read(new JsonRpcRequest("eth_getBalance", [address1, "latest"])) >> Mono.just(
new QuorumRpcReader.Result( new QuorumRpcReader.Result(
Global.objectMapper.writeValueAsBytes("0x100"), null, 1, resolvers, null Global.objectMapper.writeValueAsBytes("0x100"), null, 1, resolver
) )
) )
} }
@@ -327,7 +328,7 @@ class EthereumDirectReaderSpec extends Specification {
1 * create(_, _, _, _) >> Mock(QuorumReader) { 1 * create(_, _, _, _) >> Mock(QuorumReader) {
1 * read(new JsonRpcRequest("eth_getBalance", [address1, "0xa8c9bb"])) >> Mono.just( 1 * read(new JsonRpcRequest("eth_getBalance", [address1, "0xa8c9bb"])) >> Mono.just(
new QuorumRpcReader.Result( new QuorumRpcReader.Result(
Global.objectMapper.writeValueAsBytes("0x100"), null, 1, resolvers, null Global.objectMapper.writeValueAsBytes("0x100"), null, 1, resolver
) )
) )
} }
@@ -359,7 +360,7 @@ class EthereumDirectReaderSpec extends Specification {
} }
def result = Mono.just( def result = Mono.just(
new QuorumRpcReader.Result( new QuorumRpcReader.Result(
Global.objectMapper.writeValueAsBytes(json), null, 1, resolvers, null) Global.objectMapper.writeValueAsBytes(json), null, 1, resolver)
) )
EthereumDirectReader ethereumDirectReader = new EthereumDirectReader( EthereumDirectReader ethereumDirectReader = new EthereumDirectReader(
up, Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock() up, Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock()
@@ -402,7 +403,7 @@ class EthereumDirectReaderSpec extends Specification {
} }
def result = Mono.just( def result = Mono.just(
new QuorumRpcReader.Result( new QuorumRpcReader.Result(
Global.objectMapper.writeValueAsBytes(json), null, 1, resolvers, null) Global.objectMapper.writeValueAsBytes(json), null, 1, resolver)
) )
EthereumDirectReader ethereumDirectReader = new EthereumDirectReader( EthereumDirectReader ethereumDirectReader = new EthereumDirectReader(
up, Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock() up, Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock()