solution: upgrade Kotlin to 1.5

This commit is contained in:
Igor Artamonov
2021-09-15 21:30:05 -04:00
parent 199259afdb
commit 1576f1fe64
36 changed files with 89 additions and 70 deletions

View File

@@ -73,7 +73,7 @@ class BlocksRedisCache(
}
fun add(block: BlockContainer): Mono<Void> {
if (block.timestamp == null || block.hash == null) {
if (block.timestamp == null || block.hash == null) { //null in unit tests
return Mono.empty()
}
if (block.full) {

View File

@@ -115,7 +115,7 @@ open class Caches(
//for LATEST data cache it in memory, it may be short living so better to avoid Redis
memoizeBlock(block)
} else if (tag == Tag.REQUESTED) {
var blockOnlyContainer: BlockContainer? = null
val blockOnlyContainer: BlockContainer?
var jsonValue: BlockJson<*>? = null
if (block.full) {
jsonValue = Global.objectMapper.readValue<BlockJson<*>>(block.json, BlockJson::class.java)
@@ -130,8 +130,8 @@ open class Caches(
redisBlocksByHash?.add(blockOnlyContainer)?.let(job::add)
// now cache only transactions
jsonValue?.let { jsonValue ->
val plainTransactions = jsonValue.transactions.filterIsInstance<TransactionJson>()
jsonValue?.let { value ->
val plainTransactions = value.transactions.filterIsInstance<TransactionJson>()
if (plainTransactions.isNotEmpty()) {
val transactions = plainTransactions.map { tx ->
TxContainer.from(tx)

View File

@@ -42,6 +42,7 @@ class HeightByHashRedisCache(
private const val MAX_CACHE_TIME_MINUTES = 60L * 4
}
@Suppress("UNCHECKED_CAST")
override fun read(key: BlockId): Mono<Long> {
return redis.get(key(key))
.flatMap { data ->
@@ -54,13 +55,13 @@ class HeightByHashRedisCache(
override fun add(block: BlockContainer): Mono<Void> {
return Mono.just(block)
.flatMap { block ->
.flatMap { blockData ->
// even if block replaced, the mapping hash-long is still valid, so can be cached for long time
// even for fresh blocks
val ttl = TimeUnit.MINUTES.toSeconds(MAX_CACHE_TIME_MINUTES)
val key = key(block.hash)
val value = asBytes(block.height)
val key = key(blockData.hash)
val value = asBytes(blockData.height)
redis.setex(key, ttl, value)
}
.doOnError {

View File

@@ -90,10 +90,10 @@ abstract class OnBlockRedisCache<T>(
* Add to cache.
* Note that it returns Mono<Void> which must be subscribed to actually save
*/
open fun add(block: BlockContainer, value: T): Mono<Void> {
return Mono.just(block)
open fun add(container: BlockContainer, value: T): Mono<Void> {
return Mono.just(container)
.flatMap { block ->
val ttl = cachingTime(block.timestamp!!)
val ttl = cachingTime(block.timestamp)
if (ttl > MIN_CACHE_TIME_SECONDS) {
val key = key(block.hash)
val proto = toProto(block, value)

View File

@@ -59,8 +59,8 @@ abstract class OnTxRedisCache<T>(
return "${prefix}:${chain.id}:${hash.toHex()}"
}
fun evict(block: BlockContainer): Mono<Void> {
return Mono.just(block)
fun evict(container: BlockContainer): Mono<Void> {
return Mono.just(container)
.map { block ->
block.transactions.map {
key(it)

View File

@@ -60,24 +60,24 @@ class AuthConfigReader : YamlConfigReader() {
* ca: "ca.dshackle.test.crt"
* ```
*/
fun readServerTls(node: MappingNode?): AuthConfig.ServerTlsAuth? {
return getMapping(node, "tls")?.let { node ->
fun readServerTls(rootNode: MappingNode?): AuthConfig.ServerTlsAuth? {
return getMapping(rootNode, "tls")?.let { tlsNode ->
val auth = AuthConfig.ServerTlsAuth()
getValueAsBool(node, "enabled")?.let {
getValueAsBool(tlsNode, "enabled")?.let {
auth.enabled = it
}
if (auth.enabled != null && !auth.enabled!!) {
return null
}
getMapping(node, "server")?.let { node ->
auth.certificate = getValueAsString(node, "certificate")
auth.key = getValueAsString(node, "key")
getMapping(tlsNode, "server")?.let { serverNode ->
auth.certificate = getValueAsString(serverNode, "certificate")
auth.key = getValueAsString(serverNode, "key")
}
getMapping(node, "client")?.let { node ->
getValueAsBool(node, "require")?.let {
getMapping(tlsNode, "client")?.let { clientNode ->
getValueAsBool(clientNode, "require")?.let {
auth.clientRequire = it
}
auth.clientCa = getValueAsString(node, "ca")
auth.clientCa = getValueAsString(clientNode, "ca")
}
auth
}

View File

@@ -33,20 +33,20 @@ class CacheConfigReader : YamlConfigReader(), ConfigReader<CacheConfig> {
override fun read(input: MappingNode?): CacheConfig? {
return getMapping(input, "cache")?.let { node ->
val config = CacheConfig()
getMapping(node, "redis")?.let { node ->
getMapping(node, "redis")?.let { redisNode ->
val redis = CacheConfig.Redis()
val enabled = getValueAsBool(node, "enabled") ?: true
val enabled = getValueAsBool(redisNode, "enabled") ?: true
if (enabled) {
getValueAsString(node, "host")?.let {
getValueAsString(redisNode, "host")?.let {
redis.host = it
}
getValueAsInt(node, "port")?.let {
getValueAsInt(redisNode, "port")?.let {
redis.port = it
}
getValueAsInt(node, "db")?.let {
getValueAsInt(redisNode, "db")?.let {
redis.db = it
}
getValueAsString(node, "password")?.let {
getValueAsString(redisNode, "password")?.let {
redis.password = it
}
config.redis = redis

View File

@@ -18,6 +18,7 @@ package io.emeraldpay.dshackle.config
import org.slf4j.LoggerFactory
import org.yaml.snakeyaml.nodes.MappingNode
import java.io.InputStream
import java.util.*
class TokensConfigReader : YamlConfigReader(), ConfigReader<TokensConfig> {
@@ -38,7 +39,7 @@ class TokensConfigReader : YamlConfigReader(), ConfigReader<TokensConfig> {
token.address = getValueAsString(node, "address")
token.name = getValueAsString(node, "name")
token.type = getValueAsString(node, "type")?.let {
if (it.toUpperCase() == "ERC-20") {
if (it.uppercase(Locale.getDefault()) == "ERC-20") {
TokensConfig.Type.ERC20
} else {
log.warn("Invalid token type: $it")

View File

@@ -78,7 +78,7 @@ open class UpstreamsConfig {
var methods: Methods? = null
var role: UpstreamRole = UpstreamRole.STANDARD
@Suppress("unchecked")
@Suppress("UNCHECKED_CAST")
fun <Z : UpstreamConnection> cast(type: Class<Z>): Upstream<Z> {
if (connection == null || type.isAssignableFrom(connection!!.javaClass)) {
return this as Upstream<Z>
@@ -144,20 +144,19 @@ open class UpstreamsConfig {
DSHACKLE("dshackle", "grpc"),
UNKNOWN("unknown");
private val code: Array<String>
private val code: Array<out String>
init {
this.code = code as Array<String>
this.code = code
Arrays.sort(this.code)
}
companion object {
fun byName(code: String): UpstreamType {
var code = code
code = code.toLowerCase()
val cleanCode = code.lowercase(Locale.getDefault())
for (t in UpstreamType.values()) {
if (Arrays.binarySearch(t.code, code) >= 0) {
if (Arrays.binarySearch(t.code, cleanCode) >= 0) {
return t
}
}

View File

@@ -26,6 +26,8 @@ import java.io.InputStream
import java.lang.IllegalArgumentException
import java.net.URI
import java.time.Duration
import java.util.*
import kotlin.collections.ArrayList
class UpstreamsConfigReader(
private val fileResolver: FileResolver
@@ -83,7 +85,7 @@ class UpstreamsConfigReader(
}
}
getList<MappingNode>(input, "upstreams")?.value?.forEachIndexed { pos, upNode ->
getList<MappingNode>(input, "upstreams")?.value?.forEachIndexed { _, upNode ->
val connNode = getMapping(upNode, "connection")
if (hasAny(connNode, "ethereum")) {
val connConfigNode = getMapping(connNode, "ethereum")!!
@@ -197,7 +199,7 @@ class UpstreamsConfigReader(
getValueAsString(upNode, "role")?.let {
val name = it.trim()
try {
val role = UpstreamsConfig.UpstreamRole.valueOf(name.toUpperCase())
val role = UpstreamsConfig.UpstreamRole.valueOf(name.uppercase(Locale.getDefault()))
upstream.role = role
} catch (e: IllegalArgumentException) {
log.warn("Unsupported role `$name` for upstream ${upstream.id}")

View File

@@ -24,6 +24,7 @@ import org.yaml.snakeyaml.nodes.Node
import org.yaml.snakeyaml.nodes.ScalarNode
import java.io.InputStream
import java.io.InputStreamReader
import java.util.*
abstract class YamlConfigReader {
private val envVariables = EnvVariables()
@@ -50,6 +51,7 @@ abstract class YamlConfigReader {
}.count() > 0
}
@Suppress("UNCHECKED_CAST")
private fun <T> getValue(mappingNode: MappingNode?, key: String, type: Class<T>): T? {
if (mappingNode == null) {
return null
@@ -79,6 +81,7 @@ abstract class YamlConfigReader {
return getValue(mappingNode, key, ScalarNode::class.java)
}
@Suppress("UNCHECKED_CAST")
protected fun <T> getList(mappingNode: MappingNode?, key: String): CollectionNode<T>? {
val value = getValue(mappingNode, key, CollectionNode::class.java) ?: return null
return value as CollectionNode<T>
@@ -109,7 +112,7 @@ abstract class YamlConfigReader {
protected fun getValueAsBool(mappingNode: MappingNode?, key: String): Boolean? {
return getValue(mappingNode, key)?.let {
return@let if (it.isPlain) {
it.value?.toLowerCase() == "true"
it.value.lowercase(Locale.getDefault()) == "true"
} else {
null
}
@@ -128,8 +131,8 @@ abstract class YamlConfigReader {
fun getBlockchain(id: String): Chain {
return Chain.values().find { chain ->
chain.name == id.toUpperCase()
|| chain.chainCode.toUpperCase() == id.toUpperCase()
chain.name == id.uppercase(Locale.getDefault())
|| chain.chainCode.uppercase(Locale.getDefault()) == id.uppercase(Locale.getDefault())
|| chain.id.toString() == id
} ?: Chain.UNSPECIFIED
}

View File

@@ -23,6 +23,7 @@ abstract class SourceContainer(
private val parsed: Any?
) {
@Suppress("UNCHECKED_CAST")
fun <T> getParsed(clazz: Class<T>): T? {
if (parsed == null) {
return null

View File

@@ -103,7 +103,7 @@ class AccessLogWriter(
BufferedOutputStream(FileOutputStream(filename, true)).use { wrt ->
var limit = WRITE_BATCH_LIMIT
while (limit > 0) {
limit--
limit -= 1
val next = queue.poll() ?: return
val bytes: ByteArray? = try {
objectMapper.writeValueAsBytes(next)

View File

@@ -195,7 +195,7 @@ class EventsBuilder {
override fun onRequest(msg: BlockchainOuterClass.BalanceRequest) {
balanceRequest = Events.BalanceRequest(
msg.asset.code.toUpperCase(),
msg.asset.code.uppercase(Locale.getDefault()),
msg.address.addrTypeCase.name
)
}

View File

@@ -111,7 +111,7 @@ class ProxyServer(
serverBuilder = serverBuilder.secure { secure -> secure.sslContext(sslContext) }
}
val server: DisposableServer = serverBuilder
serverBuilder
.route(this::setupRoutes)
.bindNow()
}

View File

@@ -101,9 +101,9 @@ open class ReadRpcJson() : Function<ByteArray, ProxyCall> {
} catch (e: IllegalArgumentException) {
throw RpcException(RpcResponseError.CODE_INVALID_JSON, "Empty JSON")
}
if (first == '{'.toByte()) {
if (first == '{'.code.toByte()) {
return ProxyCall.RpcType.SINGLE
} else if (first == '['.toByte()) {
} else if (first == '['.code.toByte()) {
return ProxyCall.RpcType.BATCH
}
throw RpcException(RpcResponseError.CODE_INVALID_JSON, "Failed to parse JSON")

View File

@@ -20,7 +20,7 @@ import io.emeraldpay.dshackle.upstream.ApiSource
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
// creates instance of a Quorum based reader
open interface QuorumReaderFactory {
interface QuorumReaderFactory {
companion object {
fun default(): QuorumReaderFactory {
@@ -28,7 +28,7 @@ open interface QuorumReaderFactory {
}
}
open fun create(apis: ApiSource, quorum: CallQuorum): Reader<JsonRpcRequest, QuorumRpcReader.Result>
fun create(apis: ApiSource, quorum: CallQuorum): Reader<JsonRpcRequest, QuorumRpcReader.Result>
class Default : QuorumReaderFactory {
override fun create(apis: ApiSource, quorum: CallQuorum): Reader<JsonRpcRequest, QuorumRpcReader.Result> {

View File

@@ -33,8 +33,6 @@ import reactor.core.publisher.Flux
import reactor.core.publisher.Mono
import java.util.*
import java.util.concurrent.TimeUnit
import java.util.concurrent.locks.ReentrantLock
import kotlin.concurrent.withLock
@Service @DependsOn("monitoringSetup")
class BlockchainRpc(
@@ -82,8 +80,8 @@ class BlockchainRpc(
).doOnError { errorMetric.increment() }
}
override fun subscribeTxStatus(request: Mono<BlockchainOuterClass.TxStatusRequest>): Flux<BlockchainOuterClass.TxStatus> {
return request.flatMapMany { request ->
override fun subscribeTxStatus(requestMono: Mono<BlockchainOuterClass.TxStatusRequest>): Flux<BlockchainOuterClass.TxStatus> {
return requestMono.flatMapMany { request ->
val chain = Chain.byId(request.chainValue)
val metrics = chainMetrics.get(chain)
metrics.subscribeTxMetric.increment()
@@ -106,7 +104,7 @@ class BlockchainRpc(
val chain = Chain.byId(request.asset.chainValue)
val metrics = chainMetrics.get(chain)
metrics.subscribeBalanceMetric.increment()
val asset = request.asset.code.toLowerCase()
val asset = request.asset.code.lowercase(Locale.getDefault())
try {
trackAddress.find { it.isSupported(chain, asset) }?.let { track ->
track.subscribe(request)
@@ -129,7 +127,7 @@ class BlockchainRpc(
val chain = Chain.byId(request.asset.chainValue)
val metrics = chainMetrics.get(chain)
metrics.getBalanceMetric.increment()
val asset = request.asset.code.toLowerCase()
val asset = request.asset.code.lowercase(Locale.getDefault())
val startTime = System.currentTimeMillis()
try {
trackAddress.find { it.isSupported(chain, asset) }?.let { track ->

View File

@@ -153,7 +153,7 @@ open class NativeCall(
.forMethod(method)
.forLabels(Selector.convertToMatcher(request.selector))
val callQuorum = upstream.getMethods().getQuorumFor(method) ?: AlwaysQuorum()
val callQuorum = upstream.getMethods().getQuorumFor(method) ?: AlwaysQuorum() // can be null in tests
callQuorum.init(upstream.getHead())
// for NotLaggingQuorum it makes sense to select compatible upstreams before the call
@@ -218,6 +218,7 @@ open class NativeCall(
)
}
@Suppress("UNCHECKED_CAST")
private fun extractParams(jsonParams: String): List<Any> {
if (StringUtils.isEmpty(jsonParams)) {
return emptyList()

View File

@@ -220,7 +220,7 @@ class TrackBitcoinAddress(
if (isBalanceAvailable(chain)) {
val addresses = allAddresses(upstream, request).cache()
val following = upstream.getHead().getFlux()
.flatMap { block ->
.flatMap {
requestBalances(chain, upstream, Flux.from(addresses), request.includeUtxo)
}
val last = HashMap<String, BigInteger>()

View File

@@ -22,7 +22,9 @@ import org.springframework.stereotype.Service
import reactor.core.publisher.Flux
import reactor.core.publisher.Mono
import java.math.BigInteger
import java.util.*
import javax.annotation.PostConstruct
import kotlin.collections.HashMap
@Service
class TrackERC20Address(
@@ -41,7 +43,7 @@ class TrackERC20Address(
fun init() {
tokensConfig.tokens.forEach { token ->
val chain = token.blockchain!!
val asset = token.name!!.toLowerCase()
val asset = token.name!!.lowercase(Locale.getDefault())
val id = TokenId(chain, asset)
val definition = TokenDefinition(
chain, asset,
@@ -53,13 +55,13 @@ class TrackERC20Address(
}
override fun isSupported(chain: Chain, asset: String): Boolean {
return tokens.containsKey(TokenId(chain, asset.toLowerCase())) &&
return tokens.containsKey(TokenId(chain, asset.lowercase(Locale.getDefault()))) &&
BlockchainType.from(chain) == BlockchainType.ETHEREUM && multistreamHolder.isAvailable(chain)
}
override fun getBalance(request: BlockchainOuterClass.BalanceRequest): Flux<BlockchainOuterClass.AddressBalance> {
val chain = Chain.byId(request.asset.chainValue)
val asset = request.asset.code.toLowerCase()
val asset = request.asset.code.lowercase(Locale.getDefault())
val tokenDefinition = tokens[TokenId(chain, asset)] ?: return Flux.empty()
return ethereumAddresses.extract(request.address)
.map { TrackedAddress(chain, it, tokenDefinition.token, tokenDefinition.name) }
@@ -69,7 +71,7 @@ class TrackERC20Address(
override fun subscribe(request: BlockchainOuterClass.BalanceRequest): Flux<BlockchainOuterClass.AddressBalance> {
val chain = Chain.byId(request.asset.chainValue)
val asset = request.asset.code.toLowerCase()
val asset = request.asset.code.lowercase(Locale.getDefault())
val tokenDefinition = tokens[TokenId(chain, asset)] ?: return Flux.empty()
val head = multistreamHolder.getUpstream(chain)?.getHead()?.getFlux() ?: Flux.empty()
@@ -116,7 +118,7 @@ class TrackERC20Address(
.setBalance(address.balance!!.toString(10))
.setAsset(Common.Asset.newBuilder()
.setChainValue(address.chain.id)
.setCode(address.tokenName.toUpperCase()))
.setCode(address.tokenName.uppercase(Locale.getDefault())))
.setAddress(Common.SingleAddress.newBuilder().setAddress(address.address.toHex()))
.build()
}

View File

@@ -31,6 +31,7 @@ import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import reactor.core.publisher.Flux
import reactor.core.publisher.Mono
import java.util.*
@Service
class TrackEthereumAddress(
@@ -98,7 +99,7 @@ class TrackEthereumAddress(
if (!multistreamHolder.isAvailable(chain)) {
return Flux.error(SilentException.UnsupportedBlockchain(request.asset.chainValue))
}
if (request.asset.code?.toLowerCase() != "ether") {
if (request.asset.code.lowercase(Locale.getDefault()) != "ether") {
return Flux.error(SilentException("Unsupported asset ${request.asset.code}"))
}
return ethereumAddresses.extract(request.address).map {

View File

@@ -36,6 +36,7 @@ import reactor.core.publisher.Mono
import reactor.core.scheduler.Schedulers
import java.time.Duration
import java.time.Instant
import java.util.*
import java.util.concurrent.atomic.AtomicReference
import java.util.concurrent.locks.ReentrantLock
import java.util.function.Predicate
@@ -70,7 +71,7 @@ abstract class Multistream(
init {
UpstreamAvailability.values().forEach { status ->
Metrics.gauge("$metrics.availability",
listOf(Tag.of("chain", chain.chainCode), Tag.of("status", status.name.toLowerCase())), this) {
listOf(Tag.of("chain", chain.chainCode), Tag.of("status", status.name.lowercase(Locale.getDefault()))), this) {
upstreams.count { it.getStatus() == status }.toDouble()
}
}
@@ -187,7 +188,7 @@ abstract class Multistream(
override fun getStatus(): UpstreamAvailability {
val upstreams = getAll()
return if (upstreams.isEmpty()) UpstreamAvailability.UNAVAILABLE
else upstreams.map { it.getStatus() }.min()!!
else upstreams.minOf { it.getStatus() }
}
//TODO options for multistream are useless

View File

@@ -119,6 +119,7 @@ class Selector {
return Collections.unmodifiableCollection(matchers)
}
@Suppress("UNCHECKED_CAST")
fun <T : Matcher> getMatcher(type: Class<T>): T? {
return matchers.find { type.isAssignableFrom(it.javaClass) } as T?
}

View File

@@ -27,6 +27,7 @@ import org.slf4j.LoggerFactory
import org.springframework.context.Lifecycle
import reactor.core.publisher.Mono
@Suppress("UNCHECKED_CAST")
open class BitcoinMultistream(
chain: Chain,
val upstreams: MutableList<BitcoinUpstream>,
@@ -108,6 +109,7 @@ open class BitcoinMultistream(
return upstreams.flatMap { it.getLabels() }
}
@Suppress("UNCHECKED_CAST")
override fun <T : Upstream> cast(selfType: Class<T>): T {
if (!selfType.isAssignableFrom(this.javaClass)) {
throw ClassCastException("Cannot cast ${this.javaClass} to $selfType")

View File

@@ -78,6 +78,7 @@ open class BitcoinRpcUpstream(
return false
}
@Suppress("UNCHECKED_CAST")
override fun <T : Upstream> cast(selfType: Class<T>): T {
if (!selfType.isAssignableFrom(this.javaClass)) {
throw ClassCastException("Cannot cast ${this.javaClass} to $selfType")

View File

@@ -62,6 +62,7 @@ open class CachingMempoolData(
}
}
@Suppress("UNCHECKED_CAST")
fun fetchFromUpstream(): Mono<List<String>> {
return upstreams.getDirectApi(Selector.empty).flatMap { api ->
api.read(JsonRpcRequest("getrawmempool", emptyList()))

View File

@@ -51,6 +51,7 @@ class ExtractBlock() {
private val objectMapper: ObjectMapper = Global.objectMapper
@Suppress("UNCHECKED_CAST")
fun extract(json: ByteArray): BlockContainer {
val data = objectMapper.readValue(json, Map::class.java) as Map<String, Any>

View File

@@ -45,7 +45,7 @@ class EthereumDirectReader(
}
private val objectMapper: ObjectMapper = Global.objectMapper
open var quorumReaderFactory: QuorumReaderFactory = QuorumReaderFactory.default()
var quorumReaderFactory: QuorumReaderFactory = QuorumReaderFactory.default()
val blockReader: Reader<BlockHash, BlockContainer>
val blockByHeightReader: Reader<Long, BlockContainer>
@@ -110,6 +110,7 @@ class EthereumDirectReader(
}
}
@Suppress("UNCHECKED_CAST")
private fun readBlock(request: JsonRpcRequest, id: String): Mono<BlockContainer> {
return readWithQuorum(request)
.timeout(Defaults.timeoutInternal, Mono.error(TimeoutException("Block not read $id")))

View File

@@ -27,6 +27,7 @@ import org.slf4j.LoggerFactory
import org.springframework.context.Lifecycle
import reactor.core.publisher.Mono
@Suppress("UNCHECKED_CAST")
open class EthereumMultistream(
chain: Chain,
val upstreams: MutableList<EthereumUpstream>,
@@ -109,7 +110,7 @@ open class EthereumMultistream(
return upstreams.flatMap { it.getLabels() }
}
@SuppressWarnings("unchecked")
@Suppress("UNCHECKED_CAST")
override fun <T : Upstream> cast(selfType: Class<T>): T {
if (!selfType.isAssignableFrom(this.javaClass)) {
throw ClassCastException("Cannot cast ${this.javaClass} to $selfType")

View File

@@ -120,7 +120,7 @@ open class EthereumRpcUpstream(
return false
}
@Suppress("unchecked")
@Suppress("UNCHECKED_CAST")
override fun <T : Upstream> cast(selfType: Class<T>): T {
if (!selfType.isAssignableFrom(this.javaClass)) {
throw ClassCastException("Cannot cast ${this.javaClass} to $selfType")

View File

@@ -111,6 +111,7 @@ class BitcoinGrpcUpstream(
return true
}
@Suppress("UNCHECKED_CAST")
override fun <T : Upstream> cast(selfType: Class<T>): T {
if (!selfType.isAssignableFrom(this.javaClass)) {
throw ClassCastException("Cannot cast ${this.javaClass} to $selfType")

View File

@@ -142,7 +142,7 @@ open class EthereumGrpcUpstream(
return defaultReader
}
@SuppressWarnings("unchecked")
@Suppress("UNCHECKED_CAST")
override fun <T : Upstream> cast(selfType: Class<T>): T {
if (!selfType.isAssignableFrom(this.javaClass)) {
throw ClassCastException("Cannot cast ${this.javaClass} to $selfType")

View File

@@ -83,7 +83,7 @@ class GrpcUpstreams(
val updates = Flux.interval(Duration.ZERO, Duration.ofMinutes(1))
.flatMap {
client.describe(BlockchainOuterClass.DescribeRequest.newBuilder().build())
}.onErrorContinue { t, u ->
}.onErrorContinue { t, _ ->
if (ExceptionUtils.indexOfType(t, ConnectException::class.java) >= 0) {
log.warn("gRPC upstream $host:$port is unavailable")
known.values.forEach {