@@ -18,7 +18,9 @@ package io.emeraldpay.dshackle.config
|
||||
|
||||
import io.emeraldpay.dshackle.Defaults
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.connectors.EthereumConnectorFactory.ConnectorMode
|
||||
import org.apache.commons.lang3.ObjectUtils.firstNonNull
|
||||
import java.net.URI
|
||||
import java.time.Duration
|
||||
import java.util.Arrays
|
||||
import java.util.Locale
|
||||
|
||||
@@ -26,46 +28,67 @@ open class UpstreamsConfig {
|
||||
var defaultOptions: MutableList<DefaultOptions> = ArrayList<DefaultOptions>()
|
||||
var upstreams: MutableList<Upstream<*>> = ArrayList<Upstream<*>>()
|
||||
|
||||
open class Options {
|
||||
data class Options(
|
||||
val disableValidation: Boolean,
|
||||
val validationInterval: Int,
|
||||
val timeout: Duration,
|
||||
val providesBalance: Boolean?,
|
||||
val validatePeers: Boolean,
|
||||
val minPeers: Int,
|
||||
val validateSyncing: Boolean
|
||||
)
|
||||
|
||||
open class PartialOptions {
|
||||
var disableValidation: Boolean? = null
|
||||
var validationInterval: Int = 30
|
||||
var validationInterval: Int? = null
|
||||
set(value) {
|
||||
require(value > 0) {
|
||||
require(value == null || value > 0) {
|
||||
"validation-interval must be a positive number: $value"
|
||||
}
|
||||
field = value
|
||||
}
|
||||
var timeout = Defaults.timeout
|
||||
var timeout: Duration? = null
|
||||
var providesBalance: Boolean? = null
|
||||
var validatePeers: Boolean = true
|
||||
var minPeers: Int? = 1
|
||||
var validatePeers: Boolean? = null
|
||||
var minPeers: Int? = null
|
||||
set(value) {
|
||||
require(value != null && value >= 0) {
|
||||
require(value == null || value >= 0) {
|
||||
"min-peers must be a positive number: $value"
|
||||
}
|
||||
field = value
|
||||
}
|
||||
var validateSyncing: Boolean = true
|
||||
fun merge(overwrites: Options?): Options {
|
||||
var validateSyncing: Boolean? = null
|
||||
|
||||
fun merge(overwrites: PartialOptions?): PartialOptions {
|
||||
if (overwrites == null) {
|
||||
return this
|
||||
}
|
||||
val copy = Options()
|
||||
copy.validatePeers = this.validatePeers && overwrites.validatePeers
|
||||
copy.minPeers = if (this.minPeers != null) this.minPeers else overwrites.minPeers
|
||||
copy.disableValidation =
|
||||
if (this.disableValidation != null) this.disableValidation else overwrites.disableValidation
|
||||
copy.validationInterval = overwrites.validationInterval
|
||||
copy.providesBalance =
|
||||
if (this.providesBalance != null) this.providesBalance else overwrites.providesBalance
|
||||
copy.validateSyncing = this.validateSyncing && overwrites.validateSyncing
|
||||
val copy = PartialOptions()
|
||||
copy.validatePeers = firstNonNull(overwrites.validatePeers, this.validatePeers)
|
||||
copy.minPeers = firstNonNull(overwrites.minPeers, this.minPeers)
|
||||
copy.disableValidation = firstNonNull(overwrites.disableValidation, this.disableValidation)
|
||||
copy.validationInterval = firstNonNull(overwrites.validationInterval, this.validationInterval)
|
||||
copy.providesBalance = firstNonNull(overwrites.providesBalance, this.providesBalance)
|
||||
copy.validateSyncing = firstNonNull(overwrites.validateSyncing, this.validateSyncing)
|
||||
copy.timeout = firstNonNull(overwrites.timeout, this.timeout)
|
||||
return copy
|
||||
}
|
||||
|
||||
fun buildOptions(): Options =
|
||||
Options(
|
||||
firstNonNull(this.disableValidation, false)!!,
|
||||
firstNonNull(this.validationInterval, 30)!!,
|
||||
firstNonNull(this.timeout, Defaults.timeout)!!,
|
||||
this.providesBalance,
|
||||
firstNonNull(this.validatePeers, true)!!,
|
||||
firstNonNull(this.minPeers, 1)!!,
|
||||
firstNonNull(this.validateSyncing, true)!!
|
||||
)
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun getDefaults(): Options {
|
||||
val options = Options()
|
||||
fun getDefaults(): PartialOptions {
|
||||
val options = PartialOptions()
|
||||
options.minPeers = 1
|
||||
options.disableValidation = false
|
||||
return options
|
||||
@@ -73,16 +96,16 @@ open class UpstreamsConfig {
|
||||
}
|
||||
}
|
||||
|
||||
class DefaultOptions : Options() {
|
||||
class DefaultOptions : PartialOptions() {
|
||||
var chains: List<String>? = null
|
||||
var options: Options? = null
|
||||
var options: PartialOptions? = null
|
||||
}
|
||||
|
||||
class Upstream<T : UpstreamConnection> {
|
||||
var id: String? = null
|
||||
var nodeId: Int? = null
|
||||
var chain: String? = null
|
||||
var options: Options? = null
|
||||
var options: PartialOptions? = null
|
||||
var isEnabled = true
|
||||
var connection: T? = null
|
||||
val labels = Labels()
|
||||
|
||||
@@ -303,7 +303,7 @@ class UpstreamsConfigReader(
|
||||
}
|
||||
}
|
||||
|
||||
internal fun tryReadOptions(upNode: MappingNode): UpstreamsConfig.Options? {
|
||||
internal fun tryReadOptions(upNode: MappingNode): UpstreamsConfig.PartialOptions? {
|
||||
return if (hasAny(upNode, "options")) {
|
||||
return getMapping(upNode, "options")?.let { values ->
|
||||
readOptions(values)
|
||||
@@ -348,8 +348,8 @@ class UpstreamsConfigReader(
|
||||
}
|
||||
}
|
||||
|
||||
internal fun readOptions(values: MappingNode): UpstreamsConfig.Options {
|
||||
val options = UpstreamsConfig.Options()
|
||||
internal fun readOptions(values: MappingNode): UpstreamsConfig.PartialOptions {
|
||||
val options = UpstreamsConfig.PartialOptions()
|
||||
getValueAsBool(values, "validate-peers")?.let {
|
||||
options.validatePeers = it
|
||||
}
|
||||
|
||||
@@ -94,16 +94,17 @@ open class ConfiguredUpstreams(
|
||||
}
|
||||
log.debug("Start upstream ${up.id}")
|
||||
if (up.connection is UpstreamsConfig.GrpcConnection) {
|
||||
val options = up.options ?: UpstreamsConfig.Options()
|
||||
buildGrpcUpstream(up.nodeId, up.cast(UpstreamsConfig.GrpcConnection::class.java), options, compressionConfig.grpc.clientEnabled)
|
||||
val options = up.options ?: UpstreamsConfig.PartialOptions()
|
||||
buildGrpcUpstream(up.nodeId, up.cast(UpstreamsConfig.GrpcConnection::class.java), options.buildOptions(), compressionConfig.grpc.clientEnabled)
|
||||
} else {
|
||||
val chain = Global.chainById(up.chain)
|
||||
if (chain == Chain.UNSPECIFIED) {
|
||||
log.error("Chain is unknown: ${up.chain}")
|
||||
return@forEach
|
||||
}
|
||||
val options = (defaultOptions[chain] ?: UpstreamsConfig.Options.getDefaults())
|
||||
.merge(up.options ?: UpstreamsConfig.Options())
|
||||
val options = (defaultOptions[chain] ?: UpstreamsConfig.PartialOptions.getDefaults())
|
||||
.merge(up.options ?: UpstreamsConfig.PartialOptions())
|
||||
.buildOptions()
|
||||
val upstream = when (BlockchainType.from(chain)) {
|
||||
BlockchainType.EVM_POS -> {
|
||||
buildEthereumPosUpstream(
|
||||
@@ -140,8 +141,8 @@ open class ConfiguredUpstreams(
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildDefaultOptions(config: UpstreamsConfig): HashMap<Chain, UpstreamsConfig.Options> {
|
||||
val defaultOptions = HashMap<Chain, UpstreamsConfig.Options>()
|
||||
private fun buildDefaultOptions(config: UpstreamsConfig): HashMap<Chain, UpstreamsConfig.PartialOptions> {
|
||||
val defaultOptions = HashMap<Chain, UpstreamsConfig.PartialOptions>()
|
||||
config.defaultOptions.forEach { defaultsConfig ->
|
||||
defaultsConfig.chains?.forEach { chainName ->
|
||||
Global.chainById(chainName).let { chain ->
|
||||
|
||||
@@ -87,7 +87,7 @@ abstract class DefaultUpstream(
|
||||
}
|
||||
|
||||
private fun statusByLag(lag: Long, proposed: UpstreamAvailability): UpstreamAvailability {
|
||||
if (options.disableValidation == true) {
|
||||
if (options.disableValidation) {
|
||||
// if we specifically told that this upstream should be _always valid_ then skip
|
||||
// the status calculation and trust the proposed value as is
|
||||
return proposed
|
||||
|
||||
@@ -242,7 +242,7 @@ abstract class Multistream(
|
||||
|
||||
// TODO options for multistream are useless
|
||||
override fun getOptions(): UpstreamsConfig.Options {
|
||||
return UpstreamsConfig.Options()
|
||||
throw IllegalStateException("Options are not supported for multistream")
|
||||
}
|
||||
|
||||
// TODO roles for multistream are useless
|
||||
|
||||
@@ -102,7 +102,7 @@ open class BitcoinRpcUpstream(
|
||||
|
||||
validatorSubscription?.dispose()
|
||||
|
||||
if (getOptions().disableValidation != null && getOptions().disableValidation!!) {
|
||||
if (getOptions().disableValidation) {
|
||||
this.setLag(0)
|
||||
this.setStatus(UpstreamAvailability.OK)
|
||||
} else {
|
||||
|
||||
@@ -57,7 +57,7 @@ open class EthereumRpcUpstream(
|
||||
override fun start() {
|
||||
log.info("Configured for ${chain.chainName}")
|
||||
connector.start()
|
||||
if (getOptions().disableValidation != null && getOptions().disableValidation!!) {
|
||||
if (getOptions().disableValidation) {
|
||||
log.warn("Disable validation for upstream ${this.getId()}")
|
||||
this.setLag(0)
|
||||
this.setStatus(UpstreamAvailability.OK)
|
||||
|
||||
@@ -57,7 +57,7 @@ open class EthereumPosRpcUpstream(
|
||||
override fun start() {
|
||||
log.info("Configured for ${chain.chainName}")
|
||||
connector.start()
|
||||
if (getOptions().disableValidation != null && getOptions().disableValidation!!) {
|
||||
if (getOptions().disableValidation) {
|
||||
log.warn("Disable validation for upstream ${this.getId()}")
|
||||
this.setLag(0)
|
||||
this.setStatus(UpstreamAvailability.OK)
|
||||
|
||||
@@ -57,7 +57,7 @@ class BitcoinGrpcUpstream(
|
||||
) : BitcoinUpstream(
|
||||
"${parentId}_${chain.chainCode.lowercase(Locale.getDefault())}",
|
||||
chain,
|
||||
UpstreamsConfig.Options.getDefaults(),
|
||||
UpstreamsConfig.PartialOptions.getDefaults().buildOptions(),
|
||||
role,
|
||||
chainConfig
|
||||
),
|
||||
|
||||
@@ -63,7 +63,7 @@ open class EthereumGrpcUpstream(
|
||||
) : EthereumUpstream(
|
||||
"${parentId}_${chain.chainCode.lowercase(Locale.getDefault())}",
|
||||
hash,
|
||||
UpstreamsConfig.Options.getDefaults(),
|
||||
UpstreamsConfig.PartialOptions.getDefaults().buildOptions(),
|
||||
role,
|
||||
null,
|
||||
null,
|
||||
|
||||
@@ -57,7 +57,7 @@ open class EthereumPosGrpcUpstream(
|
||||
) : EthereumPosUpstream(
|
||||
"${parentId}_${chain.chainCode.lowercase(Locale.getDefault())}",
|
||||
hash,
|
||||
UpstreamsConfig.Options.getDefaults(),
|
||||
UpstreamsConfig.PartialOptions.getDefaults().buildOptions(),
|
||||
role,
|
||||
null,
|
||||
null,
|
||||
|
||||
Reference in New Issue
Block a user