diff --git a/src/main/kotlin/io/emeraldpay/dshackle/rpc/Describe.kt b/src/main/kotlin/io/emeraldpay/dshackle/rpc/Describe.kt index b1e112a8..31901d30 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/rpc/Describe.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/rpc/Describe.kt @@ -26,12 +26,13 @@ class Describe( chainUpstreams.getAll().let { ups -> if (ups.isNotEmpty()) { val status = subscribeStatus.chainStatus(chain, ups) - resp.addChains( - BlockchainOuterClass.DescribeChain.newBuilder() - .setChain(Common.ChainRef.forNumber(chain.id)) - .setStatus(status) - .build() - ) + val targets = chainUpstreams.getSupportedTargets() + val chainDescription = BlockchainOuterClass.DescribeChain.newBuilder() + .setChain(Common.ChainRef.forNumber(chain.id)) + .addAllSupportedTargets(targets) + .setStatus(status) + .build() + resp.addChains(chainDescription) } } } diff --git a/src/main/kotlin/io/emeraldpay/dshackle/rpc/NativeCall.kt b/src/main/kotlin/io/emeraldpay/dshackle/rpc/NativeCall.kt index 253f050c..35cfa4d2 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/rpc/NativeCall.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/rpc/NativeCall.kt @@ -32,6 +32,7 @@ class NativeCall( if (chain == Chain.UNSPECIFIED) { throw Exception("Invalid chain id: ${request.chain.number}") } + // TODO send error to all requests? val upstream = upstreams.getUpstream(chain)?.getApi() ?: throw Exception("Chain ${chain.id} is unavailable") request.itemsList.toFlux().map { val method = it.target diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/AggregatedUpstreams.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/AggregatedUpstreams.kt index d462b1d0..f6018cec 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/AggregatedUpstreams.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/AggregatedUpstreams.kt @@ -20,6 +20,14 @@ abstract class AggregatedUpstreams: Upstream { .map { it.status } } + override fun getSupportedTargets(): Set { + val list = HashSet() + getAll().forEach { + list.addAll(it.getSupportedTargets()) + } + return list + } + override fun isAvailable(): Boolean { return getAll().any { it.isAvailable() } } diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/EthereumApi.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/EthereumApi.kt index 6e86012b..df8edc32 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/EthereumApi.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/EthereumApi.kt @@ -167,4 +167,8 @@ open class EthereumApi( } throw RpcException(-32601, "Method not found") } + + fun getSupportedMethods(): Set { + return allowedMethods.plus(hardcodedMethods).toSortedSet() + } } \ No newline at end of file diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/EthereumUpstream.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/EthereumUpstream.kt index 15bc4fcc..900562c7 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/EthereumUpstream.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/EthereumUpstream.kt @@ -16,6 +16,10 @@ class EthereumUpstream( private val options: UpstreamsConfig.Options ): Upstream { + override fun getSupportedTargets(): Set { + return api.getSupportedMethods() + } + private val log = LoggerFactory.getLogger(EthereumUpstream::class.java) private val head: EthereumHead = if (ethereumWs != null) { diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/GrpcUpstream.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/GrpcUpstream.kt index e54b49a1..6f4f04c0 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/GrpcUpstream.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/GrpcUpstream.kt @@ -20,8 +20,10 @@ import reactor.core.publisher.toMono import java.lang.Exception import java.math.BigInteger import java.time.Duration +import java.util.* import java.util.concurrent.atomic.AtomicReference import java.util.function.Function +import kotlin.collections.ArrayList open class GrpcUpstream( private val chain: Chain, @@ -41,6 +43,7 @@ open class GrpcUpstream( private val head = Head(this) private val api: EthereumApi private val statusStream: TopicProcessor = TopicProcessor.create() + private val supportedMethods = HashSet() init { val grpcTransport = EthereumGrpcTransport(chain, client, objectMapper) @@ -93,6 +96,7 @@ open class GrpcUpstream( } fun init(conf: BlockchainOuterClass.DescribeChain) { + supportedMethods.addAll(conf.supportedTargetsList) conf.status?.let { status -> onStatus(status) } } @@ -110,6 +114,9 @@ open class GrpcUpstream( } // ------------------------------------------------------------------------------------------ + override fun getSupportedTargets(): Set { + return supportedMethods + } override fun isAvailable(): Boolean { return headBlock.get() != null diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/GrpcUpstreams.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/GrpcUpstreams.kt index 701077fc..5591bfef 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/GrpcUpstreams.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/GrpcUpstreams.kt @@ -56,6 +56,9 @@ class GrpcUpstreams( } chains as List } + .doOnError { t -> + log.error("Failed to get description from $host:$port", t) + } //TODO subscribe only after receiving details client.subscribeStatus(BlockchainOuterClass.StatusRequest.newBuilder().build()) .subscribe { value -> diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/Upstream.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/Upstream.kt index 77a65180..1525dd4e 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/Upstream.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/Upstream.kt @@ -10,4 +10,5 @@ interface Upstream { fun getHead(): EthereumHead fun getApi(): EthereumApi fun getOptions(): UpstreamsConfig.Options + fun getSupportedTargets(): Set } \ No newline at end of file