solution: upgrade Kotlin to 1.5
This commit is contained in:
@@ -9,7 +9,7 @@ buildscript {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.70'
|
||||
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.30'
|
||||
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.12'
|
||||
}
|
||||
}
|
||||
@@ -297,5 +297,5 @@ jacocoTestReport {
|
||||
}
|
||||
}
|
||||
jacoco {
|
||||
toolVersion = "0.8.5"
|
||||
toolVersion = "0.8.7"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
# Languages
|
||||
groovyVersion=2.5.14
|
||||
kotlinVersion=1.3.11
|
||||
kotlinVersion=1.5.30
|
||||
protocVersion=3.9.0
|
||||
# Main Libs
|
||||
slf4jVersion=1.7.25
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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}")
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
)
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ class ProxyServer(
|
||||
serverBuilder = serverBuilder.secure { secure -> secure.sslContext(sslContext) }
|
||||
}
|
||||
|
||||
val server: DisposableServer = serverBuilder
|
||||
serverBuilder
|
||||
.route(this::setupRoutes)
|
||||
.bindNow()
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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 ->
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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>()
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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?
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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()))
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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")))
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user