Merge pull request #134 from p2p-org/lag-config
added chains configuration
This commit is contained in:
@@ -315,3 +315,33 @@ For JSON RPC and Websockets a Basic Authentication can be used:
|
|||||||
|
|
||||||
- `username` - username
|
- `username` - username
|
||||||
- `password` - password
|
- `password` - password
|
||||||
|
|
||||||
|
=== Chains specific configuration
|
||||||
|
We can use chain settings to specify chain specific behavior, for example rules for dshackle to work with upstream statuses
|
||||||
|
|
||||||
|
.chains.yaml
|
||||||
|
[source,yaml]
|
||||||
|
----
|
||||||
|
chain-settings:
|
||||||
|
default:
|
||||||
|
lags:
|
||||||
|
syncing: 6
|
||||||
|
lagging: 1
|
||||||
|
chains:
|
||||||
|
- id: eth
|
||||||
|
lags:
|
||||||
|
syncing: 6
|
||||||
|
lagging: 1
|
||||||
|
- id: polygon
|
||||||
|
lags:
|
||||||
|
syncing: 20
|
||||||
|
lagging: 10
|
||||||
|
----
|
||||||
|
Options
|
||||||
|
[cols="2,5a"]
|
||||||
|
|===
|
||||||
|
| Option | Description
|
||||||
|
|
||||||
|
| `lags.syncing` | the size of the lag after which the upstream is determined to be syncing
|
||||||
|
| `lags.lagging` | the size of the lag after which the upstream is determined to be lagging
|
||||||
|
|===
|
||||||
|
|||||||
@@ -16,14 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
package io.emeraldpay.dshackle
|
package io.emeraldpay.dshackle
|
||||||
|
|
||||||
import io.emeraldpay.dshackle.config.CacheConfig
|
import io.emeraldpay.dshackle.config.*
|
||||||
import io.emeraldpay.dshackle.config.HealthConfig
|
|
||||||
import io.emeraldpay.dshackle.config.MainConfig
|
|
||||||
import io.emeraldpay.dshackle.config.MainConfigReader
|
|
||||||
import io.emeraldpay.dshackle.config.MonitoringConfig
|
|
||||||
import io.emeraldpay.dshackle.config.SignatureConfig
|
|
||||||
import io.emeraldpay.dshackle.config.TokensConfig
|
|
||||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
|
||||||
import org.bouncycastle.jce.provider.BouncyCastleProvider
|
import org.bouncycastle.jce.provider.BouncyCastleProvider
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
@@ -141,4 +134,9 @@ open class Config(
|
|||||||
open fun healthConfig(@Autowired mainConfig: MainConfig): HealthConfig {
|
open fun healthConfig(@Autowired mainConfig: MainConfig): HealthConfig {
|
||||||
return mainConfig.health
|
return mainConfig.health
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
open fun chainsConfig(mainConfig: MainConfig): ChainsConfig {
|
||||||
|
return mainConfig.chains
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,8 @@
|
|||||||
package io.emeraldpay.dshackle.config
|
package io.emeraldpay.dshackle.config
|
||||||
|
|
||||||
import org.slf4j.LoggerFactory
|
|
||||||
import org.yaml.snakeyaml.nodes.MappingNode
|
import org.yaml.snakeyaml.nodes.MappingNode
|
||||||
|
|
||||||
class AccessLogReader : YamlConfigReader(), ConfigReader<AccessLogConfig> {
|
class AccessLogReader : YamlConfigReader<AccessLogConfig>() {
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val log = LoggerFactory.getLogger(AccessLogReader::class.java)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun read(input: MappingNode?): AccessLogConfig {
|
override fun read(input: MappingNode?): AccessLogConfig {
|
||||||
return getMapping(input, "accessLog")?.let { node ->
|
return getMapping(input, "accessLog")?.let { node ->
|
||||||
val enabled = getValueAsBool(node, "enabled") ?: false
|
val enabled = getValueAsBool(node, "enabled") ?: false
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ package io.emeraldpay.dshackle.config
|
|||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.yaml.snakeyaml.nodes.MappingNode
|
import org.yaml.snakeyaml.nodes.MappingNode
|
||||||
|
|
||||||
class AuthConfigReader : YamlConfigReader() {
|
class AuthConfigReader : YamlConfigReader<AuthConfig>() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val log = LoggerFactory.getLogger(AuthConfigReader::class.java)
|
private val log = LoggerFactory.getLogger(AuthConfigReader::class.java)
|
||||||
@@ -82,4 +82,8 @@ class AuthConfigReader : YamlConfigReader() {
|
|||||||
auth
|
auth
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun read(input: MappingNode?): AuthConfig? {
|
||||||
|
return null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,19 +17,13 @@ package io.emeraldpay.dshackle.config
|
|||||||
|
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.yaml.snakeyaml.nodes.MappingNode
|
import org.yaml.snakeyaml.nodes.MappingNode
|
||||||
import java.io.InputStream
|
|
||||||
|
|
||||||
class CacheConfigReader : YamlConfigReader(), ConfigReader<CacheConfig> {
|
class CacheConfigReader : YamlConfigReader<CacheConfig>() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val log = LoggerFactory.getLogger(CacheConfigReader::class.java)
|
private val log = LoggerFactory.getLogger(CacheConfigReader::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun read(input: InputStream): CacheConfig? {
|
|
||||||
val configNode = readNode(input)
|
|
||||||
return read(configNode)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun read(input: MappingNode?): CacheConfig? {
|
override fun read(input: MappingNode?): CacheConfig? {
|
||||||
return getMapping(input, "cache")?.let { node ->
|
return getMapping(input, "cache")?.let { node ->
|
||||||
val config = CacheConfig()
|
val config = CacheConfig()
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package io.emeraldpay.dshackle.config
|
||||||
|
|
||||||
|
import io.emeraldpay.dshackle.Chain
|
||||||
|
import java.lang.IllegalStateException
|
||||||
|
|
||||||
|
data class ChainsConfig(private val chains: Map<Chain, RawChainConfig>, val currentDefault: RawChainConfig?) {
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
fun default(): ChainsConfig = ChainsConfig(emptyMap(), RawChainConfig.default())
|
||||||
|
}
|
||||||
|
|
||||||
|
data class RawChainConfig(val syncingLagSize: Int?, val laggingLagSize: Int?) {
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
fun default() = RawChainConfig(6, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class ChainConfig(val syncingLagSize: Int, val laggingLagSize: Int) {
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
fun default() = ChainConfig(6, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun resolve(chain: Chain): ChainConfig {
|
||||||
|
val default = currentDefault ?: panic()
|
||||||
|
val raw = chains[chain] ?: default
|
||||||
|
|
||||||
|
return ChainConfig(
|
||||||
|
laggingLagSize = raw.laggingLagSize ?: default.laggingLagSize ?: panic(),
|
||||||
|
syncingLagSize = raw.syncingLagSize ?: default.syncingLagSize ?: panic(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun patch(patch: ChainsConfig) = ChainsConfig(
|
||||||
|
merge(this.chains, patch.chains),
|
||||||
|
merge(this.currentDefault!!, patch.currentDefault)
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun merge(
|
||||||
|
current: RawChainConfig,
|
||||||
|
patch: RawChainConfig?
|
||||||
|
) = RawChainConfig(
|
||||||
|
syncingLagSize = patch?.syncingLagSize ?: current.syncingLagSize,
|
||||||
|
laggingLagSize = patch?.laggingLagSize ?: current.laggingLagSize
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun merge(
|
||||||
|
current: Map<Chain, RawChainConfig>,
|
||||||
|
patch: Map<Chain, RawChainConfig>
|
||||||
|
): Map<Chain, RawChainConfig> {
|
||||||
|
val currentMut = current.toMutableMap()
|
||||||
|
|
||||||
|
for (k in patch) {
|
||||||
|
currentMut.merge(k.key, k.value) { v1, v2 -> merge(v1, v2) }
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentMut.toMap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun panic(): Nothing = throw IllegalStateException("Chains settings state is illegal - default config is null")
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package io.emeraldpay.dshackle.config
|
||||||
|
|
||||||
|
import io.emeraldpay.dshackle.Global
|
||||||
|
import org.yaml.snakeyaml.nodes.CollectionNode
|
||||||
|
import org.yaml.snakeyaml.nodes.MappingNode
|
||||||
|
import java.io.InputStream
|
||||||
|
|
||||||
|
class ChainsConfigReader : YamlConfigReader<ChainsConfig>() {
|
||||||
|
|
||||||
|
private val defaultConfig = this::class.java.getResourceAsStream("/chains.yaml")!!
|
||||||
|
|
||||||
|
override fun read(input: MappingNode?): ChainsConfig {
|
||||||
|
val default = readInternal(defaultConfig)
|
||||||
|
val current = readInternal(input)
|
||||||
|
return default.patch(current)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun readInternal(input: InputStream): ChainsConfig {
|
||||||
|
val configNode = readNode(input)
|
||||||
|
return readInternal(configNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun readInternal(input: MappingNode?): ChainsConfig {
|
||||||
|
return getMapping(input, "chain-settings")?.let {
|
||||||
|
|
||||||
|
val chains = getList<MappingNode>(it, "chains")?.let {
|
||||||
|
readChains(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
val default = getMapping(it, "default")?.let {
|
||||||
|
readChain(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ChainsConfig(
|
||||||
|
chains
|
||||||
|
?.map { Global.chainById(it.first) to it.second }
|
||||||
|
?.associateBy({ it.first }, { it.second }) ?: emptyMap(),
|
||||||
|
default
|
||||||
|
)
|
||||||
|
} ?: ChainsConfig.default()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun readChain(node: MappingNode): ChainsConfig.RawChainConfig? {
|
||||||
|
return getMapping(node, "lags")?.let {
|
||||||
|
return ChainsConfig.RawChainConfig(
|
||||||
|
getValueAsInt(it, "syncing"),
|
||||||
|
getValueAsInt(it, "lagging")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun readChains(node: CollectionNode<MappingNode>): List<Pair<String, ChainsConfig.RawChainConfig>> {
|
||||||
|
return node.value.mapNotNull {
|
||||||
|
val key = getValueAsString(it, "id")
|
||||||
|
?: throw InvalidConfigYamlException(filename, it.startMark, "chain id required")
|
||||||
|
val value = readChain(it)
|
||||||
|
if (value != null) {
|
||||||
|
return@mapNotNull key to value
|
||||||
|
} else {
|
||||||
|
return@mapNotNull null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,14 +1,8 @@
|
|||||||
package io.emeraldpay.dshackle.config
|
package io.emeraldpay.dshackle.config
|
||||||
|
|
||||||
import org.yaml.snakeyaml.nodes.MappingNode
|
import org.yaml.snakeyaml.nodes.MappingNode
|
||||||
import java.io.InputStream
|
|
||||||
|
|
||||||
class CompressionConfigReader : YamlConfigReader(), ConfigReader<CompressionConfig> {
|
|
||||||
fun read(input: InputStream): CompressionConfig? {
|
|
||||||
val configNode = readNode(input)
|
|
||||||
return read(configNode)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
class CompressionConfigReader : YamlConfigReader<CompressionConfig>() {
|
||||||
override fun read(input: MappingNode?): CompressionConfig {
|
override fun read(input: MappingNode?): CompressionConfig {
|
||||||
val config = CompressionConfig()
|
val config = CompressionConfig()
|
||||||
getMapping(input, "compression")?.let { node ->
|
getMapping(input, "compression")?.let { node ->
|
||||||
|
|||||||
@@ -20,19 +20,13 @@ import io.emeraldpay.dshackle.Global
|
|||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.yaml.snakeyaml.nodes.CollectionNode
|
import org.yaml.snakeyaml.nodes.CollectionNode
|
||||||
import org.yaml.snakeyaml.nodes.MappingNode
|
import org.yaml.snakeyaml.nodes.MappingNode
|
||||||
import java.io.InputStream
|
|
||||||
|
|
||||||
class HealthConfigReader : YamlConfigReader(), ConfigReader<HealthConfig> {
|
class HealthConfigReader : YamlConfigReader<HealthConfig>() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val log = LoggerFactory.getLogger(HealthConfigReader::class.java)
|
private val log = LoggerFactory.getLogger(HealthConfigReader::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun read(input: InputStream): HealthConfig {
|
|
||||||
val configNode = readNode(input)
|
|
||||||
return read(configNode)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun read(input: MappingNode?): HealthConfig {
|
override fun read(input: MappingNode?): HealthConfig {
|
||||||
return readInternal(getMapping(input, "health"))
|
return readInternal(getMapping(input, "health"))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,4 +29,5 @@ class MainConfig {
|
|||||||
var health: HealthConfig = HealthConfig.default()
|
var health: HealthConfig = HealthConfig.default()
|
||||||
var signature: SignatureConfig? = null
|
var signature: SignatureConfig? = null
|
||||||
var compression: CompressionConfig = CompressionConfig.default()
|
var compression: CompressionConfig = CompressionConfig.default()
|
||||||
|
var chains: ChainsConfig = ChainsConfig.default()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,17 +16,11 @@
|
|||||||
package io.emeraldpay.dshackle.config
|
package io.emeraldpay.dshackle.config
|
||||||
|
|
||||||
import io.emeraldpay.dshackle.FileResolver
|
import io.emeraldpay.dshackle.FileResolver
|
||||||
import org.slf4j.LoggerFactory
|
|
||||||
import org.yaml.snakeyaml.nodes.MappingNode
|
import org.yaml.snakeyaml.nodes.MappingNode
|
||||||
import java.io.InputStream
|
|
||||||
|
|
||||||
class MainConfigReader(
|
class MainConfigReader(
|
||||||
fileResolver: FileResolver
|
fileResolver: FileResolver
|
||||||
) : YamlConfigReader(), ConfigReader<MainConfig> {
|
) : YamlConfigReader<MainConfig>() {
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val log = LoggerFactory.getLogger(MainConfigReader::class.java)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val authConfigReader = AuthConfigReader()
|
private val authConfigReader = AuthConfigReader()
|
||||||
private val proxyConfigReader = ProxyConfigReader()
|
private val proxyConfigReader = ProxyConfigReader()
|
||||||
@@ -38,13 +32,9 @@ class MainConfigReader(
|
|||||||
private val healthConfigReader = HealthConfigReader()
|
private val healthConfigReader = HealthConfigReader()
|
||||||
private val signatureConfigReader = SignatureConfigReader(fileResolver)
|
private val signatureConfigReader = SignatureConfigReader(fileResolver)
|
||||||
private val compressionConfigReader = CompressionConfigReader()
|
private val compressionConfigReader = CompressionConfigReader()
|
||||||
|
private val chainsConfigReader = ChainsConfigReader()
|
||||||
|
|
||||||
fun read(input: InputStream): MainConfig? {
|
override fun read(input: MappingNode?): MainConfig {
|
||||||
val configNode = readNode(input)
|
|
||||||
return read(configNode)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun read(input: MappingNode?): MainConfig? {
|
|
||||||
val config = MainConfig()
|
val config = MainConfig()
|
||||||
getValueAsString(input, "host")?.let {
|
getValueAsString(input, "host")?.let {
|
||||||
config.host = it
|
config.host = it
|
||||||
@@ -87,6 +77,9 @@ class MainConfigReader(
|
|||||||
compressionConfigReader.read(input).let {
|
compressionConfigReader.read(input).let {
|
||||||
config.compression = it
|
config.compression = it
|
||||||
}
|
}
|
||||||
|
chainsConfigReader.read(input).let {
|
||||||
|
config.chains = it
|
||||||
|
}
|
||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,21 +15,9 @@
|
|||||||
*/
|
*/
|
||||||
package io.emeraldpay.dshackle.config
|
package io.emeraldpay.dshackle.config
|
||||||
|
|
||||||
import org.slf4j.LoggerFactory
|
|
||||||
import org.yaml.snakeyaml.nodes.MappingNode
|
import org.yaml.snakeyaml.nodes.MappingNode
|
||||||
import java.io.InputStream
|
|
||||||
|
|
||||||
class MonitoringConfigReader : YamlConfigReader(), ConfigReader<MonitoringConfig> {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val log = LoggerFactory.getLogger(MonitoringConfigReader::class.java)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun read(input: InputStream): MonitoringConfig {
|
|
||||||
val configNode = readNode(input)
|
|
||||||
return read(configNode)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
class MonitoringConfigReader : YamlConfigReader<MonitoringConfig>() {
|
||||||
override fun read(input: MappingNode?): MonitoringConfig {
|
override fun read(input: MappingNode?): MonitoringConfig {
|
||||||
return readInternal(getMapping(input, "monitoring"))
|
return readInternal(getMapping(input, "monitoring"))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,25 +21,18 @@ import io.emeraldpay.dshackle.Global
|
|||||||
import org.apache.commons.lang3.StringUtils
|
import org.apache.commons.lang3.StringUtils
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.yaml.snakeyaml.nodes.MappingNode
|
import org.yaml.snakeyaml.nodes.MappingNode
|
||||||
import java.io.InputStream
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read YAML config, part related to Proxy configuration
|
* Read YAML config, part related to Proxy configuration
|
||||||
*/
|
*/
|
||||||
class ProxyConfigReader : YamlConfigReader(), ConfigReader<ProxyConfig> {
|
class ProxyConfigReader : YamlConfigReader<ProxyConfig>() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val log = LoggerFactory.getLogger(ProxyConfigReader::class.java)
|
private val log = LoggerFactory.getLogger(ProxyConfigReader::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var filename = "dshackle.yaml"
|
|
||||||
private val authConfigReader = AuthConfigReader()
|
private val authConfigReader = AuthConfigReader()
|
||||||
|
|
||||||
fun read(input: InputStream): ProxyConfig? {
|
|
||||||
val configNode = readNode(input)
|
|
||||||
return read(configNode)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun read(input: MappingNode?): ProxyConfig? {
|
override fun read(input: MappingNode?): ProxyConfig? {
|
||||||
return readInternal(getMapping(input, "proxy"))
|
return readInternal(getMapping(input, "proxy"))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,9 @@
|
|||||||
package io.emeraldpay.dshackle.config
|
package io.emeraldpay.dshackle.config
|
||||||
|
|
||||||
import io.emeraldpay.dshackle.FileResolver
|
import io.emeraldpay.dshackle.FileResolver
|
||||||
import org.slf4j.LoggerFactory
|
|
||||||
import org.yaml.snakeyaml.nodes.MappingNode
|
import org.yaml.snakeyaml.nodes.MappingNode
|
||||||
import java.io.InputStream
|
|
||||||
|
|
||||||
class SignatureConfigReader(val fileResolver: FileResolver) : YamlConfigReader(), ConfigReader<SignatureConfig> {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val log = LoggerFactory.getLogger(SignatureConfig::class.java)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun read(input: InputStream): SignatureConfig? {
|
|
||||||
val configNode = readNode(input)
|
|
||||||
return read(configNode)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
class SignatureConfigReader(val fileResolver: FileResolver) : YamlConfigReader<SignatureConfig>() {
|
||||||
override fun read(input: MappingNode?): SignatureConfig? {
|
override fun read(input: MappingNode?): SignatureConfig? {
|
||||||
return getMapping(input, "signed-response")?.let { node ->
|
return getMapping(input, "signed-response")?.let { node ->
|
||||||
val config = SignatureConfig()
|
val config = SignatureConfig()
|
||||||
|
|||||||
@@ -18,18 +18,12 @@ package io.emeraldpay.dshackle.config
|
|||||||
import io.emeraldpay.dshackle.Global
|
import io.emeraldpay.dshackle.Global
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.yaml.snakeyaml.nodes.MappingNode
|
import org.yaml.snakeyaml.nodes.MappingNode
|
||||||
import java.io.InputStream
|
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
class TokensConfigReader : YamlConfigReader(), ConfigReader<TokensConfig> {
|
class TokensConfigReader : YamlConfigReader<TokensConfig>() {
|
||||||
|
|
||||||
private val log = LoggerFactory.getLogger(TokensConfigReader::class.java)
|
private val log = LoggerFactory.getLogger(TokensConfigReader::class.java)
|
||||||
|
|
||||||
fun read(input: InputStream): TokensConfig? {
|
|
||||||
val configNode = readNode(input)
|
|
||||||
return read(configNode)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun read(input: MappingNode?): TokensConfig? {
|
override fun read(input: MappingNode?): TokensConfig? {
|
||||||
val tokens = getList<MappingNode>(input, "tokens")?.value?.map { node ->
|
val tokens = getList<MappingNode>(input, "tokens")?.value?.map { node ->
|
||||||
val token = TokensConfig.Token()
|
val token = TokensConfig.Token()
|
||||||
|
|||||||
@@ -27,24 +27,23 @@ import java.util.Locale
|
|||||||
|
|
||||||
class UpstreamsConfigReader(
|
class UpstreamsConfigReader(
|
||||||
private val fileResolver: FileResolver
|
private val fileResolver: FileResolver
|
||||||
) : YamlConfigReader(), ConfigReader<UpstreamsConfig> {
|
) : YamlConfigReader<UpstreamsConfig>() {
|
||||||
|
|
||||||
private val log = LoggerFactory.getLogger(UpstreamsConfigReader::class.java)
|
private val log = LoggerFactory.getLogger(UpstreamsConfigReader::class.java)
|
||||||
private val authConfigReader = AuthConfigReader()
|
private val authConfigReader = AuthConfigReader()
|
||||||
private val knownNodeIds: MutableSet<Int> = HashSet()
|
private val knownNodeIds: MutableSet<Int> = HashSet()
|
||||||
|
|
||||||
fun read(input: InputStream): UpstreamsConfig? {
|
|
||||||
val configNode = readNode(input)
|
|
||||||
return readInternal(configNode)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun read(input: MappingNode?): UpstreamsConfig? {
|
override fun read(input: MappingNode?): UpstreamsConfig? {
|
||||||
return getMapping(input, "cluster")?.let {
|
return getMapping(input, "cluster")?.let {
|
||||||
readInternal(it)
|
readInternal(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun readInternal(input: MappingNode?): UpstreamsConfig? {
|
fun readInternal(input: InputStream): UpstreamsConfig? {
|
||||||
|
val configNode = readNode(input)
|
||||||
|
return readInternal(configNode)
|
||||||
|
}
|
||||||
|
fun readInternal(input: MappingNode?): UpstreamsConfig {
|
||||||
val config = UpstreamsConfig()
|
val config = UpstreamsConfig()
|
||||||
|
|
||||||
getList<MappingNode>(input, "defaults")?.value?.forEach { opts ->
|
getList<MappingNode>(input, "defaults")?.value?.forEach { opts ->
|
||||||
@@ -61,7 +60,7 @@ class UpstreamsConfigReader(
|
|||||||
getValueAsString(input, "include")?.let { path ->
|
getValueAsString(input, "include")?.let { path ->
|
||||||
fileResolver.resolve(path).let { file ->
|
fileResolver.resolve(path).let { file ->
|
||||||
if (file.exists() && file.isFile && file.canRead()) {
|
if (file.exists() && file.isFile && file.canRead()) {
|
||||||
read(file.inputStream())?.let {
|
readInternal(file.inputStream())?.let {
|
||||||
it.upstreams.forEach { upstream -> config.upstreams.add(upstream) }
|
it.upstreams.forEach { upstream -> config.upstreams.add(upstream) }
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -73,7 +72,7 @@ class UpstreamsConfigReader(
|
|||||||
getListOfString(input, "include")?.forEach { path ->
|
getListOfString(input, "include")?.forEach { path ->
|
||||||
fileResolver.resolve(path).let { file ->
|
fileResolver.resolve(path).let { file ->
|
||||||
if (file.exists() && file.isFile && file.canRead()) {
|
if (file.exists() && file.isFile && file.canRead()) {
|
||||||
read(file.inputStream())?.let {
|
readInternal(file.inputStream())?.let {
|
||||||
it.upstreams.forEach { upstream -> config.upstreams.add(upstream) }
|
it.upstreams.forEach { upstream -> config.upstreams.add(upstream) }
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -25,9 +25,15 @@ import java.io.InputStream
|
|||||||
import java.io.InputStreamReader
|
import java.io.InputStreamReader
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
abstract class YamlConfigReader {
|
abstract class YamlConfigReader<T> : ConfigReader<T> {
|
||||||
private val envVariables = EnvVariables()
|
private val envVariables = EnvVariables()
|
||||||
|
|
||||||
|
val filename = "dshackle.yaml"
|
||||||
|
|
||||||
|
fun read(input: InputStream): T? {
|
||||||
|
val configNode = readNode(input)
|
||||||
|
return read(configNode)
|
||||||
|
}
|
||||||
fun readNode(input: String): MappingNode {
|
fun readNode(input: String): MappingNode {
|
||||||
return readNode(input.byteInputStream())
|
return readNode(input.byteInputStream())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import io.emeraldpay.dshackle.BlockchainType
|
|||||||
import io.emeraldpay.dshackle.Chain
|
import io.emeraldpay.dshackle.Chain
|
||||||
import io.emeraldpay.dshackle.FileResolver
|
import io.emeraldpay.dshackle.FileResolver
|
||||||
import io.emeraldpay.dshackle.Global
|
import io.emeraldpay.dshackle.Global
|
||||||
|
import io.emeraldpay.dshackle.config.ChainsConfig
|
||||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||||
import io.emeraldpay.dshackle.reader.JsonRpcReader
|
import io.emeraldpay.dshackle.reader.JsonRpcReader
|
||||||
import io.emeraldpay.dshackle.upstream.*
|
import io.emeraldpay.dshackle.upstream.*
|
||||||
@@ -64,7 +65,8 @@ open class ConfiguredUpstreams(
|
|||||||
private val callTargets: CallTargetsHolder,
|
private val callTargets: CallTargetsHolder,
|
||||||
private val eventPublisher: ApplicationEventPublisher,
|
private val eventPublisher: ApplicationEventPublisher,
|
||||||
@Qualifier("grpcChannelExecutor")
|
@Qualifier("grpcChannelExecutor")
|
||||||
private val channelExecutor: Executor
|
private val channelExecutor: Executor,
|
||||||
|
private val chainsConfig: ChainsConfig
|
||||||
) : ApplicationRunner {
|
) : ApplicationRunner {
|
||||||
|
|
||||||
private val log = LoggerFactory.getLogger(ConfiguredUpstreams::class.java)
|
private val log = LoggerFactory.getLogger(ConfiguredUpstreams::class.java)
|
||||||
@@ -95,11 +97,22 @@ open class ConfiguredUpstreams(
|
|||||||
.merge(defaultOptions[chain] ?: UpstreamsConfig.Options.getDefaults())
|
.merge(defaultOptions[chain] ?: UpstreamsConfig.Options.getDefaults())
|
||||||
val upstream = when (BlockchainType.from(chain)) {
|
val upstream = when (BlockchainType.from(chain)) {
|
||||||
BlockchainType.EVM_POW -> {
|
BlockchainType.EVM_POW -> {
|
||||||
buildEthereumUpstream(up.nodeId, up.cast(UpstreamsConfig.EthereumConnection::class.java), chain, options)
|
buildEthereumUpstream(
|
||||||
|
up.nodeId,
|
||||||
|
up.cast(UpstreamsConfig.EthereumConnection::class.java),
|
||||||
|
chain,
|
||||||
|
options,
|
||||||
|
chainsConfig.resolve(chain)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockchainType.BITCOIN -> {
|
BlockchainType.BITCOIN -> {
|
||||||
buildBitcoinUpstream(up.cast(UpstreamsConfig.BitcoinConnection::class.java), chain, options)
|
buildBitcoinUpstream(
|
||||||
|
up.cast(UpstreamsConfig.BitcoinConnection::class.java),
|
||||||
|
chain,
|
||||||
|
options,
|
||||||
|
chainsConfig.resolve(chain)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockchainType.EVM_POS -> {
|
BlockchainType.EVM_POS -> {
|
||||||
@@ -107,7 +120,8 @@ open class ConfiguredUpstreams(
|
|||||||
up.nodeId,
|
up.nodeId,
|
||||||
up.cast(UpstreamsConfig.EthereumPosConnection::class.java),
|
up.cast(UpstreamsConfig.EthereumPosConnection::class.java),
|
||||||
chain,
|
chain,
|
||||||
options
|
options,
|
||||||
|
chainsConfig.resolve(chain)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -167,7 +181,8 @@ open class ConfiguredUpstreams(
|
|||||||
nodeId: Int?,
|
nodeId: Int?,
|
||||||
config: UpstreamsConfig.Upstream<UpstreamsConfig.EthereumPosConnection>,
|
config: UpstreamsConfig.Upstream<UpstreamsConfig.EthereumPosConnection>,
|
||||||
chain: Chain,
|
chain: Chain,
|
||||||
options: UpstreamsConfig.Options
|
options: UpstreamsConfig.Options,
|
||||||
|
chainConf: ChainsConfig.ChainConfig
|
||||||
): Upstream? {
|
): Upstream? {
|
||||||
val conn = config.connection!!
|
val conn = config.connection!!
|
||||||
val execution = conn.execution
|
val execution = conn.execution
|
||||||
@@ -200,7 +215,8 @@ open class ConfiguredUpstreams(
|
|||||||
options, config.role,
|
options, config.role,
|
||||||
methods,
|
methods,
|
||||||
QuorumForLabels.QuorumItem(1, config.labels),
|
QuorumForLabels.QuorumItem(1, config.labels),
|
||||||
connectorFactory
|
connectorFactory,
|
||||||
|
chainConf
|
||||||
)
|
)
|
||||||
upstream.start()
|
upstream.start()
|
||||||
return upstream
|
return upstream
|
||||||
@@ -209,7 +225,8 @@ open class ConfiguredUpstreams(
|
|||||||
private fun buildBitcoinUpstream(
|
private fun buildBitcoinUpstream(
|
||||||
config: UpstreamsConfig.Upstream<UpstreamsConfig.BitcoinConnection>,
|
config: UpstreamsConfig.Upstream<UpstreamsConfig.BitcoinConnection>,
|
||||||
chain: Chain,
|
chain: Chain,
|
||||||
options: UpstreamsConfig.Options
|
options: UpstreamsConfig.Options,
|
||||||
|
chainConf: ChainsConfig.ChainConfig
|
||||||
): Upstream? {
|
): Upstream? {
|
||||||
val conn = config.connection!!
|
val conn = config.connection!!
|
||||||
val httpFactory = buildHttpFactory(conn)
|
val httpFactory = buildHttpFactory(conn)
|
||||||
@@ -242,7 +259,7 @@ open class ConfiguredUpstreams(
|
|||||||
chain, directApi, head,
|
chain, directApi, head,
|
||||||
options, config.role,
|
options, config.role,
|
||||||
QuorumForLabels.QuorumItem(1, config.labels),
|
QuorumForLabels.QuorumItem(1, config.labels),
|
||||||
methods, esplora
|
methods, esplora, chainConf
|
||||||
)
|
)
|
||||||
upstream.start()
|
upstream.start()
|
||||||
return upstream
|
return upstream
|
||||||
@@ -252,7 +269,8 @@ open class ConfiguredUpstreams(
|
|||||||
nodeId: Int?,
|
nodeId: Int?,
|
||||||
config: UpstreamsConfig.Upstream<UpstreamsConfig.EthereumConnection>,
|
config: UpstreamsConfig.Upstream<UpstreamsConfig.EthereumConnection>,
|
||||||
chain: Chain,
|
chain: Chain,
|
||||||
options: UpstreamsConfig.Options
|
options: UpstreamsConfig.Options,
|
||||||
|
chainConf: ChainsConfig.ChainConfig
|
||||||
): EthereumRpcUpstream? {
|
): EthereumRpcUpstream? {
|
||||||
val conn = config.connection!!
|
val conn = config.connection!!
|
||||||
|
|
||||||
@@ -279,7 +297,8 @@ open class ConfiguredUpstreams(
|
|||||||
options, config.role,
|
options, config.role,
|
||||||
methods,
|
methods,
|
||||||
QuorumForLabels.QuorumItem(1, config.labels),
|
QuorumForLabels.QuorumItem(1, config.labels),
|
||||||
connectorFactory
|
connectorFactory,
|
||||||
|
chainConf
|
||||||
)
|
)
|
||||||
upstream.start()
|
upstream.start()
|
||||||
return upstream
|
return upstream
|
||||||
@@ -309,7 +328,8 @@ open class ConfiguredUpstreams(
|
|||||||
endpoint.upstreamRating,
|
endpoint.upstreamRating,
|
||||||
config.labels,
|
config.labels,
|
||||||
grpcUpstreamsScheduler,
|
grpcUpstreamsScheduler,
|
||||||
channelExecutor
|
channelExecutor,
|
||||||
|
chainsConfig
|
||||||
).apply {
|
).apply {
|
||||||
timeout = options.timeout
|
timeout = options.timeout
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package io.emeraldpay.dshackle.upstream
|
package io.emeraldpay.dshackle.upstream
|
||||||
|
|
||||||
import io.emeraldpay.api.proto.BlockchainOuterClass
|
import io.emeraldpay.api.proto.BlockchainOuterClass
|
||||||
|
import io.emeraldpay.dshackle.config.ChainsConfig
|
||||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||||
import io.emeraldpay.dshackle.startup.QuorumForLabels
|
import io.emeraldpay.dshackle.startup.QuorumForLabels
|
||||||
import io.emeraldpay.dshackle.upstream.calls.CallMethods
|
import io.emeraldpay.dshackle.upstream.calls.CallMethods
|
||||||
@@ -33,36 +34,20 @@ abstract class DefaultUpstream(
|
|||||||
private val options: UpstreamsConfig.Options,
|
private val options: UpstreamsConfig.Options,
|
||||||
private val role: UpstreamsConfig.UpstreamRole,
|
private val role: UpstreamsConfig.UpstreamRole,
|
||||||
private val targets: CallMethods?,
|
private val targets: CallMethods?,
|
||||||
private val node: QuorumForLabels.QuorumItem?
|
node: QuorumForLabels.QuorumItem?,
|
||||||
|
private val chainConfig: ChainsConfig.ChainConfig
|
||||||
) : Upstream {
|
) : Upstream {
|
||||||
|
|
||||||
constructor(
|
|
||||||
id: String,
|
|
||||||
hash: Byte,
|
|
||||||
options: UpstreamsConfig.Options,
|
|
||||||
role: UpstreamsConfig.UpstreamRole,
|
|
||||||
targets: CallMethods?
|
|
||||||
) :
|
|
||||||
this(
|
|
||||||
id,
|
|
||||||
hash,
|
|
||||||
Long.MAX_VALUE,
|
|
||||||
UpstreamAvailability.UNAVAILABLE,
|
|
||||||
options,
|
|
||||||
role,
|
|
||||||
targets,
|
|
||||||
QuorumForLabels.QuorumItem.empty()
|
|
||||||
)
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
id: String,
|
id: String,
|
||||||
hash: Byte,
|
hash: Byte,
|
||||||
options: UpstreamsConfig.Options,
|
options: UpstreamsConfig.Options,
|
||||||
role: UpstreamsConfig.UpstreamRole,
|
role: UpstreamsConfig.UpstreamRole,
|
||||||
targets: CallMethods?,
|
targets: CallMethods?,
|
||||||
node: QuorumForLabels.QuorumItem?
|
node: QuorumForLabels.QuorumItem?,
|
||||||
|
chainConfig: ChainsConfig.ChainConfig
|
||||||
) :
|
) :
|
||||||
this(id, hash, Long.MAX_VALUE, UpstreamAvailability.UNAVAILABLE, options, role, targets, node)
|
this(id, hash, Long.MAX_VALUE, UpstreamAvailability.UNAVAILABLE, options, role, targets, node, chainConfig)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val log = LoggerFactory.getLogger(DefaultUpstream::class.java)
|
private val log = LoggerFactory.getLogger(DefaultUpstream::class.java)
|
||||||
@@ -111,8 +96,8 @@ abstract class DefaultUpstream(
|
|||||||
}
|
}
|
||||||
return if (proposed == UpstreamAvailability.OK) {
|
return if (proposed == UpstreamAvailability.OK) {
|
||||||
when {
|
when {
|
||||||
lag > 6 -> UpstreamAvailability.SYNCING
|
lag > chainConfig.syncingLagSize -> UpstreamAvailability.SYNCING
|
||||||
lag > 1 -> UpstreamAvailability.LAGGING
|
lag > chainConfig.laggingLagSize -> UpstreamAvailability.LAGGING
|
||||||
else -> proposed
|
else -> proposed
|
||||||
}
|
}
|
||||||
} else proposed
|
} else proposed
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
package io.emeraldpay.dshackle.upstream.bitcoin
|
package io.emeraldpay.dshackle.upstream.bitcoin
|
||||||
|
|
||||||
import io.emeraldpay.dshackle.Chain
|
import io.emeraldpay.dshackle.Chain
|
||||||
|
import io.emeraldpay.dshackle.config.ChainsConfig
|
||||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||||
import io.emeraldpay.dshackle.reader.JsonRpcReader
|
import io.emeraldpay.dshackle.reader.JsonRpcReader
|
||||||
import io.emeraldpay.dshackle.startup.QuorumForLabels
|
import io.emeraldpay.dshackle.startup.QuorumForLabels
|
||||||
@@ -37,8 +38,9 @@ open class BitcoinRpcUpstream(
|
|||||||
role: UpstreamsConfig.UpstreamRole,
|
role: UpstreamsConfig.UpstreamRole,
|
||||||
node: QuorumForLabels.QuorumItem,
|
node: QuorumForLabels.QuorumItem,
|
||||||
callMethods: CallMethods,
|
callMethods: CallMethods,
|
||||||
esploraClient: EsploraClient? = null
|
esploraClient: EsploraClient? = null,
|
||||||
) : BitcoinUpstream(id, chain, options, role, callMethods, node, esploraClient), Lifecycle {
|
chainConfig: ChainsConfig.ChainConfig
|
||||||
|
) : BitcoinUpstream(id, chain, options, role, callMethods, node, esploraClient, chainConfig), Lifecycle {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val log = LoggerFactory.getLogger(BitcoinRpcUpstream::class.java)
|
private val log = LoggerFactory.getLogger(BitcoinRpcUpstream::class.java)
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
package io.emeraldpay.dshackle.upstream.bitcoin
|
package io.emeraldpay.dshackle.upstream.bitcoin
|
||||||
|
|
||||||
import io.emeraldpay.dshackle.Chain
|
import io.emeraldpay.dshackle.Chain
|
||||||
|
import io.emeraldpay.dshackle.config.ChainsConfig
|
||||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||||
import io.emeraldpay.dshackle.startup.QuorumForLabels
|
import io.emeraldpay.dshackle.startup.QuorumForLabels
|
||||||
import io.emeraldpay.dshackle.upstream.DefaultUpstream
|
import io.emeraldpay.dshackle.upstream.DefaultUpstream
|
||||||
@@ -30,15 +31,17 @@ abstract class BitcoinUpstream(
|
|||||||
role: UpstreamsConfig.UpstreamRole,
|
role: UpstreamsConfig.UpstreamRole,
|
||||||
callMethods: CallMethods,
|
callMethods: CallMethods,
|
||||||
node: QuorumForLabels.QuorumItem,
|
node: QuorumForLabels.QuorumItem,
|
||||||
val esploraClient: EsploraClient? = null
|
val esploraClient: EsploraClient? = null,
|
||||||
) : DefaultUpstream(id, 0.toByte(), options, role, callMethods, node) {
|
private val chainConfig: ChainsConfig.ChainConfig
|
||||||
|
) : DefaultUpstream(id, 0.toByte(), options, role, callMethods, node, chainConfig) {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
id: String,
|
id: String,
|
||||||
chain: Chain,
|
chain: Chain,
|
||||||
options: UpstreamsConfig.Options,
|
options: UpstreamsConfig.Options,
|
||||||
role: UpstreamsConfig.UpstreamRole
|
role: UpstreamsConfig.UpstreamRole,
|
||||||
) : this(id, chain, options, role, DefaultBitcoinMethods(), QuorumForLabels.QuorumItem.empty())
|
chainConfig: ChainsConfig.ChainConfig
|
||||||
|
) : this(id, chain, options, role, DefaultBitcoinMethods(), QuorumForLabels.QuorumItem.empty(), null, chainConfig)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val log = LoggerFactory.getLogger(BitcoinUpstream::class.java)
|
private val log = LoggerFactory.getLogger(BitcoinUpstream::class.java)
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package io.emeraldpay.dshackle.upstream.ethereum
|
|||||||
import io.emeraldpay.dshackle.Chain
|
import io.emeraldpay.dshackle.Chain
|
||||||
import io.emeraldpay.dshackle.cache.Caches
|
import io.emeraldpay.dshackle.cache.Caches
|
||||||
import io.emeraldpay.dshackle.cache.CachesEnabled
|
import io.emeraldpay.dshackle.cache.CachesEnabled
|
||||||
|
import io.emeraldpay.dshackle.config.ChainsConfig
|
||||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||||
import io.emeraldpay.dshackle.reader.JsonRpcReader
|
import io.emeraldpay.dshackle.reader.JsonRpcReader
|
||||||
import io.emeraldpay.dshackle.startup.QuorumForLabels
|
import io.emeraldpay.dshackle.startup.QuorumForLabels
|
||||||
@@ -40,8 +41,9 @@ open class EthereumRpcUpstream(
|
|||||||
role: UpstreamsConfig.UpstreamRole,
|
role: UpstreamsConfig.UpstreamRole,
|
||||||
targets: CallMethods?,
|
targets: CallMethods?,
|
||||||
private val node: QuorumForLabels.QuorumItem?,
|
private val node: QuorumForLabels.QuorumItem?,
|
||||||
connectorFactory: ConnectorFactory
|
connectorFactory: ConnectorFactory,
|
||||||
) : EthereumUpstream(id, hash, options, role, targets, node), Lifecycle, Upstream, CachesEnabled {
|
chainConfig: ChainsConfig.ChainConfig
|
||||||
|
) : EthereumUpstream(id, hash, options, role, targets, node, chainConfig), Lifecycle, Upstream, CachesEnabled {
|
||||||
private val log = LoggerFactory.getLogger(EthereumRpcUpstream::class.java)
|
private val log = LoggerFactory.getLogger(EthereumRpcUpstream::class.java)
|
||||||
private val validator: EthereumUpstreamValidator = EthereumUpstreamValidator(this, getOptions())
|
private val validator: EthereumUpstreamValidator = EthereumUpstreamValidator(this, getOptions())
|
||||||
private val connector: EthereumConnector = connectorFactory.create(this, validator, chain)
|
private val connector: EthereumConnector = connectorFactory.create(this, validator, chain)
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
package io.emeraldpay.dshackle.upstream.ethereum
|
package io.emeraldpay.dshackle.upstream.ethereum
|
||||||
|
|
||||||
|
import io.emeraldpay.dshackle.config.ChainsConfig
|
||||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||||
import io.emeraldpay.dshackle.startup.QuorumForLabels
|
import io.emeraldpay.dshackle.startup.QuorumForLabels
|
||||||
import io.emeraldpay.dshackle.upstream.Capability
|
import io.emeraldpay.dshackle.upstream.Capability
|
||||||
@@ -28,8 +29,9 @@ abstract class EthereumUpstream(
|
|||||||
options: UpstreamsConfig.Options,
|
options: UpstreamsConfig.Options,
|
||||||
role: UpstreamsConfig.UpstreamRole,
|
role: UpstreamsConfig.UpstreamRole,
|
||||||
targets: CallMethods?,
|
targets: CallMethods?,
|
||||||
private val node: QuorumForLabels.QuorumItem?
|
private val node: QuorumForLabels.QuorumItem?,
|
||||||
) : DefaultUpstream(id, hash, options, role, targets, node) {
|
chainConfig: ChainsConfig.ChainConfig
|
||||||
|
) : DefaultUpstream(id, hash, options, role, targets, node, chainConfig) {
|
||||||
|
|
||||||
private val capabilities = if (options.providesBalance != false) {
|
private val capabilities = if (options.providesBalance != false) {
|
||||||
setOf(Capability.RPC, Capability.BALANCE)
|
setOf(Capability.RPC, Capability.BALANCE)
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package io.emeraldpay.dshackle.upstream.ethereum
|
|||||||
import io.emeraldpay.dshackle.Chain
|
import io.emeraldpay.dshackle.Chain
|
||||||
import io.emeraldpay.dshackle.cache.Caches
|
import io.emeraldpay.dshackle.cache.Caches
|
||||||
import io.emeraldpay.dshackle.cache.CachesEnabled
|
import io.emeraldpay.dshackle.cache.CachesEnabled
|
||||||
|
import io.emeraldpay.dshackle.config.ChainsConfig
|
||||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||||
import io.emeraldpay.dshackle.reader.JsonRpcReader
|
import io.emeraldpay.dshackle.reader.JsonRpcReader
|
||||||
import io.emeraldpay.dshackle.startup.QuorumForLabels
|
import io.emeraldpay.dshackle.startup.QuorumForLabels
|
||||||
@@ -39,9 +40,10 @@ open class EthereumPosRpcUpstream(
|
|||||||
options: UpstreamsConfig.Options,
|
options: UpstreamsConfig.Options,
|
||||||
role: UpstreamsConfig.UpstreamRole,
|
role: UpstreamsConfig.UpstreamRole,
|
||||||
targets: CallMethods?,
|
targets: CallMethods?,
|
||||||
private val node: QuorumForLabels.QuorumItem?,
|
node: QuorumForLabels.QuorumItem?,
|
||||||
connectorFactory: ConnectorFactory
|
connectorFactory: ConnectorFactory,
|
||||||
) : EthereumPosUpstream(id, hash, options, role, targets, node), Lifecycle, Upstream, CachesEnabled {
|
chainConfig: ChainsConfig.ChainConfig
|
||||||
|
) : EthereumPosUpstream(id, hash, options, role, targets, node, chainConfig), Lifecycle, Upstream, CachesEnabled {
|
||||||
private val log = LoggerFactory.getLogger(EthereumPosRpcUpstream::class.java)
|
private val log = LoggerFactory.getLogger(EthereumPosRpcUpstream::class.java)
|
||||||
private val validator: EthereumUpstreamValidator = EthereumUpstreamValidator(this, getOptions())
|
private val validator: EthereumUpstreamValidator = EthereumUpstreamValidator(this, getOptions())
|
||||||
private val connector: EthereumConnector = connectorFactory.create(this, validator, chain)
|
private val connector: EthereumConnector = connectorFactory.create(this, validator, chain)
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
package io.emeraldpay.dshackle.upstream.ethereum
|
package io.emeraldpay.dshackle.upstream.ethereum
|
||||||
|
|
||||||
|
import io.emeraldpay.dshackle.config.ChainsConfig
|
||||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||||
import io.emeraldpay.dshackle.startup.QuorumForLabels
|
import io.emeraldpay.dshackle.startup.QuorumForLabels
|
||||||
import io.emeraldpay.dshackle.upstream.Capability
|
import io.emeraldpay.dshackle.upstream.Capability
|
||||||
@@ -28,8 +29,9 @@ abstract class EthereumPosUpstream(
|
|||||||
options: UpstreamsConfig.Options,
|
options: UpstreamsConfig.Options,
|
||||||
role: UpstreamsConfig.UpstreamRole,
|
role: UpstreamsConfig.UpstreamRole,
|
||||||
targets: CallMethods?,
|
targets: CallMethods?,
|
||||||
private val node: QuorumForLabels.QuorumItem?
|
private val node: QuorumForLabels.QuorumItem?,
|
||||||
) : DefaultUpstream(id, hash, options, role, targets, node) {
|
chainConfig: ChainsConfig.ChainConfig
|
||||||
|
) : DefaultUpstream(id, hash, options, role, targets, node, chainConfig) {
|
||||||
|
|
||||||
private val capabilities = if (options.providesBalance != false) {
|
private val capabilities = if (options.providesBalance != false) {
|
||||||
setOf(Capability.RPC, Capability.BALANCE)
|
setOf(Capability.RPC, Capability.BALANCE)
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import io.emeraldpay.api.proto.BlockchainOuterClass
|
|||||||
import io.emeraldpay.api.proto.ReactorBlockchainGrpc
|
import io.emeraldpay.api.proto.ReactorBlockchainGrpc
|
||||||
import io.emeraldpay.dshackle.Chain
|
import io.emeraldpay.dshackle.Chain
|
||||||
import io.emeraldpay.dshackle.Defaults
|
import io.emeraldpay.dshackle.Defaults
|
||||||
|
import io.emeraldpay.dshackle.config.ChainsConfig
|
||||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||||
import io.emeraldpay.dshackle.data.BlockContainer
|
import io.emeraldpay.dshackle.data.BlockContainer
|
||||||
import io.emeraldpay.dshackle.data.BlockId
|
import io.emeraldpay.dshackle.data.BlockId
|
||||||
@@ -51,12 +52,14 @@ class BitcoinGrpcUpstream(
|
|||||||
chain: Chain,
|
chain: Chain,
|
||||||
val remote: ReactorBlockchainGrpc.ReactorBlockchainStub,
|
val remote: ReactorBlockchainGrpc.ReactorBlockchainStub,
|
||||||
private val client: JsonRpcGrpcClient,
|
private val client: JsonRpcGrpcClient,
|
||||||
overrideLabels: UpstreamsConfig.Labels?
|
overrideLabels: UpstreamsConfig.Labels?,
|
||||||
|
chainConfig: ChainsConfig.ChainConfig
|
||||||
) : BitcoinUpstream(
|
) : BitcoinUpstream(
|
||||||
"${parentId}_${chain.chainCode.lowercase(Locale.getDefault())}",
|
"${parentId}_${chain.chainCode.lowercase(Locale.getDefault())}",
|
||||||
chain,
|
chain,
|
||||||
UpstreamsConfig.Options.getDefaults(),
|
UpstreamsConfig.Options.getDefaults(),
|
||||||
role
|
role,
|
||||||
|
chainConfig
|
||||||
),
|
),
|
||||||
GrpcUpstream,
|
GrpcUpstream,
|
||||||
Lifecycle {
|
Lifecycle {
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import io.emeraldpay.api.proto.BlockchainOuterClass
|
|||||||
import io.emeraldpay.api.proto.ReactorBlockchainGrpc.ReactorBlockchainStub
|
import io.emeraldpay.api.proto.ReactorBlockchainGrpc.ReactorBlockchainStub
|
||||||
import io.emeraldpay.dshackle.Chain
|
import io.emeraldpay.dshackle.Chain
|
||||||
import io.emeraldpay.dshackle.Defaults
|
import io.emeraldpay.dshackle.Defaults
|
||||||
|
import io.emeraldpay.dshackle.config.ChainsConfig
|
||||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||||
import io.emeraldpay.dshackle.data.BlockContainer
|
import io.emeraldpay.dshackle.data.BlockContainer
|
||||||
import io.emeraldpay.dshackle.data.BlockId
|
import io.emeraldpay.dshackle.data.BlockId
|
||||||
@@ -57,14 +58,16 @@ open class EthereumGrpcUpstream(
|
|||||||
private val chain: Chain,
|
private val chain: Chain,
|
||||||
private val remote: ReactorBlockchainStub,
|
private val remote: ReactorBlockchainStub,
|
||||||
private val client: JsonRpcGrpcClient,
|
private val client: JsonRpcGrpcClient,
|
||||||
overrideLabels: UpstreamsConfig.Labels?
|
overrideLabels: UpstreamsConfig.Labels?,
|
||||||
|
chainConfig: ChainsConfig.ChainConfig
|
||||||
) : EthereumUpstream(
|
) : EthereumUpstream(
|
||||||
"${parentId}_${chain.chainCode.lowercase(Locale.getDefault())}",
|
"${parentId}_${chain.chainCode.lowercase(Locale.getDefault())}",
|
||||||
hash,
|
hash,
|
||||||
UpstreamsConfig.Options.getDefaults(),
|
UpstreamsConfig.Options.getDefaults(),
|
||||||
role,
|
role,
|
||||||
null,
|
null,
|
||||||
null
|
null,
|
||||||
|
chainConfig
|
||||||
),
|
),
|
||||||
GrpcUpstream,
|
GrpcUpstream,
|
||||||
Lifecycle {
|
Lifecycle {
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import io.emeraldpay.api.proto.BlockchainOuterClass
|
|||||||
import io.emeraldpay.api.proto.ReactorBlockchainGrpc
|
import io.emeraldpay.api.proto.ReactorBlockchainGrpc
|
||||||
import io.emeraldpay.dshackle.Chain
|
import io.emeraldpay.dshackle.Chain
|
||||||
import io.emeraldpay.dshackle.Defaults
|
import io.emeraldpay.dshackle.Defaults
|
||||||
|
import io.emeraldpay.dshackle.config.ChainsConfig
|
||||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||||
import io.emeraldpay.dshackle.data.BlockContainer
|
import io.emeraldpay.dshackle.data.BlockContainer
|
||||||
import io.emeraldpay.dshackle.data.BlockId
|
import io.emeraldpay.dshackle.data.BlockId
|
||||||
@@ -58,13 +59,16 @@ open class EthereumPosGrpcUpstream(
|
|||||||
private val remote: ReactorBlockchainGrpc.ReactorBlockchainStub,
|
private val remote: ReactorBlockchainGrpc.ReactorBlockchainStub,
|
||||||
client: JsonRpcGrpcClient,
|
client: JsonRpcGrpcClient,
|
||||||
nodeRating: Int,
|
nodeRating: Int,
|
||||||
overrideLabels: UpstreamsConfig.Labels?
|
overrideLabels: UpstreamsConfig.Labels?,
|
||||||
|
chainConfig: ChainsConfig.ChainConfig
|
||||||
) : EthereumPosUpstream(
|
) : EthereumPosUpstream(
|
||||||
"${parentId}_${chain.chainCode.lowercase(Locale.getDefault())}",
|
"${parentId}_${chain.chainCode.lowercase(Locale.getDefault())}",
|
||||||
hash,
|
hash,
|
||||||
UpstreamsConfig.Options.getDefaults(),
|
UpstreamsConfig.Options.getDefaults(),
|
||||||
role,
|
role,
|
||||||
null, null
|
null,
|
||||||
|
null,
|
||||||
|
chainConfig
|
||||||
),
|
),
|
||||||
GrpcUpstream,
|
GrpcUpstream,
|
||||||
Lifecycle {
|
Lifecycle {
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import io.emeraldpay.dshackle.Chain
|
|||||||
import io.emeraldpay.dshackle.Defaults
|
import io.emeraldpay.dshackle.Defaults
|
||||||
import io.emeraldpay.dshackle.FileResolver
|
import io.emeraldpay.dshackle.FileResolver
|
||||||
import io.emeraldpay.dshackle.config.AuthConfig
|
import io.emeraldpay.dshackle.config.AuthConfig
|
||||||
|
import io.emeraldpay.dshackle.config.ChainsConfig
|
||||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||||
import io.emeraldpay.dshackle.startup.UpstreamChangeEvent
|
import io.emeraldpay.dshackle.startup.UpstreamChangeEvent
|
||||||
import io.emeraldpay.dshackle.upstream.DefaultUpstream
|
import io.emeraldpay.dshackle.upstream.DefaultUpstream
|
||||||
@@ -64,7 +65,8 @@ class GrpcUpstreams(
|
|||||||
private val nodeRating: Int,
|
private val nodeRating: Int,
|
||||||
private val labels: UpstreamsConfig.Labels,
|
private val labels: UpstreamsConfig.Labels,
|
||||||
private val chainStatusScheduler: Scheduler,
|
private val chainStatusScheduler: Scheduler,
|
||||||
private val grpcExecutor: Executor
|
private val grpcExecutor: Executor,
|
||||||
|
private val chainsConfig: ChainsConfig
|
||||||
) {
|
) {
|
||||||
private val log = LoggerFactory.getLogger(GrpcUpstreams::class.java)
|
private val log = LoggerFactory.getLogger(GrpcUpstreams::class.java)
|
||||||
|
|
||||||
@@ -185,13 +187,13 @@ class GrpcUpstreams(
|
|||||||
|
|
||||||
private val creators: Map<BlockchainType, (chain: Chain, client: JsonRpcGrpcClient) -> DefaultUpstream> = mapOf(
|
private val creators: Map<BlockchainType, (chain: Chain, client: JsonRpcGrpcClient) -> DefaultUpstream> = mapOf(
|
||||||
BlockchainType.EVM_POW to { chain, rpcClient ->
|
BlockchainType.EVM_POW to { chain, rpcClient ->
|
||||||
EthereumGrpcUpstream(id, hash, role, chain, client, rpcClient, labels)
|
EthereumGrpcUpstream(id, hash, role, chain, client, rpcClient, labels, chainsConfig.resolve(chain))
|
||||||
},
|
},
|
||||||
BlockchainType.EVM_POS to { chain, rpcClient ->
|
BlockchainType.EVM_POS to { chain, rpcClient ->
|
||||||
EthereumPosGrpcUpstream(id, hash, role, chain, client, rpcClient, nodeRating, labels)
|
EthereumPosGrpcUpstream(id, hash, role, chain, client, rpcClient, nodeRating, labels, chainsConfig.resolve(chain))
|
||||||
},
|
},
|
||||||
BlockchainType.BITCOIN to { chain, rpcClient ->
|
BlockchainType.BITCOIN to { chain, rpcClient ->
|
||||||
BitcoinGrpcUpstream(id, role, chain, client, rpcClient, labels)
|
BitcoinGrpcUpstream(id, role, chain, client, rpcClient, labels, chainsConfig.resolve(chain))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
16
src/main/resources/chains.yaml
Normal file
16
src/main/resources/chains.yaml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
version: v1
|
||||||
|
|
||||||
|
chain-settings:
|
||||||
|
default:
|
||||||
|
lags:
|
||||||
|
syncing: 6
|
||||||
|
lagging: 1
|
||||||
|
chains:
|
||||||
|
- id: eth
|
||||||
|
lags:
|
||||||
|
syncing: 6
|
||||||
|
lagging: 1
|
||||||
|
- id: polygon
|
||||||
|
lags:
|
||||||
|
syncing: 20
|
||||||
|
lagging: 10
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2019 ETCDEV GmbH
|
||||||
|
* Copyright (c) 2020 EmeraldPay, Inc
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package io.emeraldpay.dshackle.config
|
||||||
|
|
||||||
|
import io.emeraldpay.dshackle.Chain
|
||||||
|
import spock.lang.Specification
|
||||||
|
|
||||||
|
class ChainsConfigReaderSpec extends Specification {
|
||||||
|
|
||||||
|
ChainsConfigReader reader = new ChainsConfigReader()
|
||||||
|
|
||||||
|
def "Parse standard config"() {
|
||||||
|
setup:
|
||||||
|
def stream = this.class.getClassLoader().getResourceAsStream("configs/chains-basic.yaml")
|
||||||
|
when:
|
||||||
|
def config = reader.read(stream)
|
||||||
|
def eth = config.resolve(Chain.ETHEREUM)
|
||||||
|
def pol = config.resolve(Chain.POLYGON)
|
||||||
|
def opt = config.resolve(Chain.OPTIMISM)
|
||||||
|
def sep = config.resolve(Chain.TESTNET_SEPOLIA)
|
||||||
|
then:
|
||||||
|
eth.laggingLagSize == 1
|
||||||
|
eth.syncingLagSize == 6
|
||||||
|
|
||||||
|
pol.laggingLagSize == 10
|
||||||
|
pol.syncingLagSize == 20
|
||||||
|
|
||||||
|
opt.laggingLagSize == 3
|
||||||
|
opt.syncingLagSize == 6
|
||||||
|
|
||||||
|
sep.laggingLagSize == 1
|
||||||
|
sep.syncingLagSize == 10
|
||||||
|
|
||||||
|
eth.laggingLagSize == 1
|
||||||
|
eth.syncingLagSize == 6
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,7 +27,7 @@ class UpstreamsConfigReaderSpec extends Specification {
|
|||||||
setup:
|
setup:
|
||||||
def config = this.class.getClassLoader().getResourceAsStream("configs/upstreams-basic.yaml")
|
def config = this.class.getClassLoader().getResourceAsStream("configs/upstreams-basic.yaml")
|
||||||
when:
|
when:
|
||||||
def act = reader.read(config)
|
def act = reader.readInternal(config)
|
||||||
then:
|
then:
|
||||||
act != null
|
act != null
|
||||||
with(act.defaultOptions) {
|
with(act.defaultOptions) {
|
||||||
@@ -75,7 +75,7 @@ class UpstreamsConfigReaderSpec extends Specification {
|
|||||||
setup:
|
setup:
|
||||||
def config = this.class.getClassLoader().getResourceAsStream("configs/upstreams-ws-only.yaml")
|
def config = this.class.getClassLoader().getResourceAsStream("configs/upstreams-ws-only.yaml")
|
||||||
when:
|
when:
|
||||||
def act = reader.read(config)
|
def act = reader.readInternal(config)
|
||||||
then:
|
then:
|
||||||
act != null
|
act != null
|
||||||
act.upstreams.size() == 1
|
act.upstreams.size() == 1
|
||||||
@@ -100,7 +100,7 @@ class UpstreamsConfigReaderSpec extends Specification {
|
|||||||
setup:
|
setup:
|
||||||
def config = this.class.getClassLoader().getResourceAsStream("configs/upstreams-ws-full.yaml")
|
def config = this.class.getClassLoader().getResourceAsStream("configs/upstreams-ws-full.yaml")
|
||||||
when:
|
when:
|
||||||
def act = reader.read(config)
|
def act = reader.readInternal(config)
|
||||||
then:
|
then:
|
||||||
act != null
|
act != null
|
||||||
act.upstreams.size() == 1
|
act.upstreams.size() == 1
|
||||||
@@ -127,7 +127,7 @@ class UpstreamsConfigReaderSpec extends Specification {
|
|||||||
setup:
|
setup:
|
||||||
def config = this.class.getClassLoader().getResourceAsStream("configs/upstreams-bitcoin.yaml")
|
def config = this.class.getClassLoader().getResourceAsStream("configs/upstreams-bitcoin.yaml")
|
||||||
when:
|
when:
|
||||||
def act = reader.read(config)
|
def act = reader.readInternal(config)
|
||||||
then:
|
then:
|
||||||
act != null
|
act != null
|
||||||
with(act.defaultOptions) {
|
with(act.defaultOptions) {
|
||||||
@@ -155,7 +155,7 @@ class UpstreamsConfigReaderSpec extends Specification {
|
|||||||
setup:
|
setup:
|
||||||
def config = this.class.getClassLoader().getResourceAsStream("upstreams-ethereum-pos.yaml")
|
def config = this.class.getClassLoader().getResourceAsStream("upstreams-ethereum-pos.yaml")
|
||||||
when:
|
when:
|
||||||
def act = reader.read(config)
|
def act = reader.readInternal(config)
|
||||||
then:
|
then:
|
||||||
act != null
|
act != null
|
||||||
act.upstreams.size() == 1
|
act.upstreams.size() == 1
|
||||||
@@ -175,7 +175,7 @@ class UpstreamsConfigReaderSpec extends Specification {
|
|||||||
setup:
|
setup:
|
||||||
def config = this.class.getClassLoader().getResourceAsStream("configs/upstreams-bitcoin-esplora.yaml")
|
def config = this.class.getClassLoader().getResourceAsStream("configs/upstreams-bitcoin-esplora.yaml")
|
||||||
when:
|
when:
|
||||||
def act = reader.read(config)
|
def act = reader.readInternal(config)
|
||||||
then:
|
then:
|
||||||
act != null
|
act != null
|
||||||
with(act.defaultOptions) {
|
with(act.defaultOptions) {
|
||||||
@@ -204,7 +204,7 @@ class UpstreamsConfigReaderSpec extends Specification {
|
|||||||
setup:
|
setup:
|
||||||
def config = this.class.getClassLoader().getResourceAsStream("configs/upstreams-ds.yaml")
|
def config = this.class.getClassLoader().getResourceAsStream("configs/upstreams-ds.yaml")
|
||||||
when:
|
when:
|
||||||
def act = reader.read(config)
|
def act = reader.readInternal(config)
|
||||||
then:
|
then:
|
||||||
act != null
|
act != null
|
||||||
act.upstreams.size() == 1
|
act.upstreams.size() == 1
|
||||||
@@ -227,7 +227,7 @@ class UpstreamsConfigReaderSpec extends Specification {
|
|||||||
setup:
|
setup:
|
||||||
def config = this.class.getClassLoader().getResourceAsStream("configs/upstreams-labels.yaml")
|
def config = this.class.getClassLoader().getResourceAsStream("configs/upstreams-labels.yaml")
|
||||||
when:
|
when:
|
||||||
def act = reader.read(config)
|
def act = reader.readInternal(config)
|
||||||
then:
|
then:
|
||||||
act != null
|
act != null
|
||||||
act.upstreams.size() == 2
|
act.upstreams.size() == 2
|
||||||
@@ -248,7 +248,7 @@ class UpstreamsConfigReaderSpec extends Specification {
|
|||||||
setup:
|
setup:
|
||||||
def config = this.class.getClassLoader().getResourceAsStream("configs/upstreams-options.yaml")
|
def config = this.class.getClassLoader().getResourceAsStream("configs/upstreams-options.yaml")
|
||||||
when:
|
when:
|
||||||
def act = reader.read(config)
|
def act = reader.readInternal(config)
|
||||||
then:
|
then:
|
||||||
act != null
|
act != null
|
||||||
act.upstreams.size() == 2
|
act.upstreams.size() == 2
|
||||||
@@ -264,7 +264,7 @@ class UpstreamsConfigReaderSpec extends Specification {
|
|||||||
setup:
|
setup:
|
||||||
def config = this.class.getClassLoader().getResourceAsStream("configs/upstreams-no-defaults.yaml")
|
def config = this.class.getClassLoader().getResourceAsStream("configs/upstreams-no-defaults.yaml")
|
||||||
when:
|
when:
|
||||||
def act = reader.read(config)
|
def act = reader.readInternal(config)
|
||||||
then:
|
then:
|
||||||
act != null
|
act != null
|
||||||
with(act.defaultOptions) {
|
with(act.defaultOptions) {
|
||||||
@@ -287,7 +287,7 @@ class UpstreamsConfigReaderSpec extends Specification {
|
|||||||
setup:
|
setup:
|
||||||
def config = this.class.getClassLoader().getResourceAsStream("configs/upstreams-methods.yaml")
|
def config = this.class.getClassLoader().getResourceAsStream("configs/upstreams-methods.yaml")
|
||||||
when:
|
when:
|
||||||
def act = reader.read(config)
|
def act = reader.readInternal(config)
|
||||||
then:
|
then:
|
||||||
act != null
|
act != null
|
||||||
with(act.upstreams.get(0)) {
|
with(act.upstreams.get(0)) {
|
||||||
@@ -307,7 +307,7 @@ class UpstreamsConfigReaderSpec extends Specification {
|
|||||||
setup:
|
setup:
|
||||||
def config = this.class.getClassLoader().getResourceAsStream("configs/upstreams-methods-quorum.yaml")
|
def config = this.class.getClassLoader().getResourceAsStream("configs/upstreams-methods-quorum.yaml")
|
||||||
when:
|
when:
|
||||||
def act = reader.read(config)
|
def act = reader.readInternal(config)
|
||||||
then:
|
then:
|
||||||
act != null
|
act != null
|
||||||
with(act.upstreams.get(0)) {
|
with(act.upstreams.get(0)) {
|
||||||
@@ -330,7 +330,7 @@ class UpstreamsConfigReaderSpec extends Specification {
|
|||||||
setup:
|
setup:
|
||||||
def config = this.class.getClassLoader().getResourceAsStream("configs/upstreams-no-id.yaml")
|
def config = this.class.getClassLoader().getResourceAsStream("configs/upstreams-no-id.yaml")
|
||||||
when:
|
when:
|
||||||
def act = reader.read(config)
|
def act = reader.readInternal(config)
|
||||||
then:
|
then:
|
||||||
act != null
|
act != null
|
||||||
act.upstreams.size() == 1
|
act.upstreams.size() == 1
|
||||||
@@ -357,7 +357,7 @@ class UpstreamsConfigReaderSpec extends Specification {
|
|||||||
setup:
|
setup:
|
||||||
def config = this.class.getClassLoader().getResourceAsStream("configs/upstreams-basic.yaml")
|
def config = this.class.getClassLoader().getResourceAsStream("configs/upstreams-basic.yaml")
|
||||||
when:
|
when:
|
||||||
def act = reader.read(config)
|
def act = reader.readInternal(config)
|
||||||
then:
|
then:
|
||||||
act != null
|
act != null
|
||||||
act.upstreams.size() == 2
|
act.upstreams.size() == 2
|
||||||
@@ -369,7 +369,7 @@ class UpstreamsConfigReaderSpec extends Specification {
|
|||||||
setup:
|
setup:
|
||||||
def config = this.class.getClassLoader().getResourceAsStream("configs/upstreams-roles.yaml")
|
def config = this.class.getClassLoader().getResourceAsStream("configs/upstreams-roles.yaml")
|
||||||
when:
|
when:
|
||||||
def act = reader.read(config)
|
def act = reader.readInternal(config)
|
||||||
then:
|
then:
|
||||||
act != null
|
act != null
|
||||||
act.upstreams.size() == 2
|
act.upstreams.size() == 2
|
||||||
@@ -381,7 +381,7 @@ class UpstreamsConfigReaderSpec extends Specification {
|
|||||||
setup:
|
setup:
|
||||||
def config = this.class.getClassLoader().getResourceAsStream("configs/upstreams-roles-2.yaml")
|
def config = this.class.getClassLoader().getResourceAsStream("configs/upstreams-roles-2.yaml")
|
||||||
when:
|
when:
|
||||||
def act = reader.read(config)
|
def act = reader.readInternal(config)
|
||||||
then:
|
then:
|
||||||
act != null
|
act != null
|
||||||
act.upstreams.size() == 3
|
act.upstreams.size() == 3
|
||||||
@@ -394,7 +394,7 @@ class UpstreamsConfigReaderSpec extends Specification {
|
|||||||
setup:
|
setup:
|
||||||
def config = this.class.getClassLoader().getResourceAsStream("configs/upstreams-roles-invalid.yaml")
|
def config = this.class.getClassLoader().getResourceAsStream("configs/upstreams-roles-invalid.yaml")
|
||||||
when:
|
when:
|
||||||
def act = reader.read(config)
|
def act = reader.readInternal(config)
|
||||||
then:
|
then:
|
||||||
act != null
|
act != null
|
||||||
act.upstreams.size() == 2
|
act.upstreams.size() == 2
|
||||||
@@ -406,7 +406,7 @@ class UpstreamsConfigReaderSpec extends Specification {
|
|||||||
setup:
|
setup:
|
||||||
def config = this.class.getClassLoader().getResourceAsStream("upstreams-node-id.yaml")
|
def config = this.class.getClassLoader().getResourceAsStream("upstreams-node-id.yaml")
|
||||||
when:
|
when:
|
||||||
def act = reader.read(config)
|
def act = reader.readInternal(config)
|
||||||
then:
|
then:
|
||||||
act != null
|
act != null
|
||||||
act.upstreams.size() == 2
|
act.upstreams.size() == 2
|
||||||
@@ -424,7 +424,7 @@ class UpstreamsConfigReaderSpec extends Specification {
|
|||||||
setup:
|
setup:
|
||||||
def config = this.class.getClassLoader().getResourceAsStream("upstreams-method-groups.yaml")
|
def config = this.class.getClassLoader().getResourceAsStream("upstreams-method-groups.yaml")
|
||||||
when:
|
when:
|
||||||
def act = reader.read(config)
|
def act = reader.readInternal(config)
|
||||||
then:
|
then:
|
||||||
act != null
|
act != null
|
||||||
act.upstreams.size() == 1
|
act.upstreams.size() == 1
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package io.emeraldpay.dshackle.config
|
package io.emeraldpay.dshackle.config
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable
|
||||||
import org.yaml.snakeyaml.Yaml
|
import org.yaml.snakeyaml.Yaml
|
||||||
import org.yaml.snakeyaml.nodes.MappingNode
|
import org.yaml.snakeyaml.nodes.MappingNode
|
||||||
import spock.lang.Specification
|
import spock.lang.Specification
|
||||||
@@ -41,5 +42,10 @@ class YamlConfigReaderSpec extends Specification {
|
|||||||
return new Yaml().compose(new StringReader("$key: $value")) as MappingNode
|
return new Yaml().compose(new StringReader("$key: $value")) as MappingNode
|
||||||
}
|
}
|
||||||
|
|
||||||
class Impl extends YamlConfigReader {}
|
class Impl extends YamlConfigReader {
|
||||||
|
@Override
|
||||||
|
Object read(@Nullable MappingNode input) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package io.emeraldpay.dshackle.startup
|
package io.emeraldpay.dshackle.startup
|
||||||
|
|
||||||
import io.emeraldpay.dshackle.FileResolver
|
import io.emeraldpay.dshackle.FileResolver
|
||||||
|
import io.emeraldpay.dshackle.config.ChainsConfig
|
||||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||||
import io.emeraldpay.dshackle.quorum.NonEmptyQuorum
|
import io.emeraldpay.dshackle.quorum.NonEmptyQuorum
|
||||||
import io.emeraldpay.dshackle.upstream.CallTargetsHolder
|
import io.emeraldpay.dshackle.upstream.CallTargetsHolder
|
||||||
@@ -23,7 +24,8 @@ class ConfiguredUpstreamsSpec extends Specification {
|
|||||||
Stub(UpstreamsConfig),
|
Stub(UpstreamsConfig),
|
||||||
callTargetsHolder,
|
callTargetsHolder,
|
||||||
Mock(ApplicationEventPublisher),
|
Mock(ApplicationEventPublisher),
|
||||||
Executors.newFixedThreadPool(1)
|
Executors.newFixedThreadPool(1),
|
||||||
|
ChainsConfig.default()
|
||||||
)
|
)
|
||||||
def methods = new UpstreamsConfig.Methods(
|
def methods = new UpstreamsConfig.Methods(
|
||||||
[
|
[
|
||||||
@@ -49,7 +51,8 @@ class ConfiguredUpstreamsSpec extends Specification {
|
|||||||
Stub(UpstreamsConfig),
|
Stub(UpstreamsConfig),
|
||||||
callTargetsHolder,
|
callTargetsHolder,
|
||||||
Mock(ApplicationEventPublisher),
|
Mock(ApplicationEventPublisher),
|
||||||
Executors.newFixedThreadPool(1)
|
Executors.newFixedThreadPool(1),
|
||||||
|
ChainsConfig.default()
|
||||||
)
|
)
|
||||||
def methods = new UpstreamsConfig.Methods(
|
def methods = new UpstreamsConfig.Methods(
|
||||||
[
|
[
|
||||||
@@ -74,7 +77,8 @@ class ConfiguredUpstreamsSpec extends Specification {
|
|||||||
Stub(UpstreamsConfig),
|
Stub(UpstreamsConfig),
|
||||||
callTargetsHolder,
|
callTargetsHolder,
|
||||||
Mock(ApplicationEventPublisher),
|
Mock(ApplicationEventPublisher),
|
||||||
Executors.newFixedThreadPool(1)
|
Executors.newFixedThreadPool(1),
|
||||||
|
ChainsConfig.default()
|
||||||
)
|
)
|
||||||
expect:
|
expect:
|
||||||
configurer.getHash(node, src) == expected
|
configurer.getHash(node, src) == expected
|
||||||
@@ -94,7 +98,8 @@ class ConfiguredUpstreamsSpec extends Specification {
|
|||||||
Stub(UpstreamsConfig),
|
Stub(UpstreamsConfig),
|
||||||
callTargetsHolder,
|
callTargetsHolder,
|
||||||
Mock(ApplicationEventPublisher),
|
Mock(ApplicationEventPublisher),
|
||||||
Executors.newFixedThreadPool(1)
|
Executors.newFixedThreadPool(1),
|
||||||
|
ChainsConfig.default()
|
||||||
)
|
)
|
||||||
when:
|
when:
|
||||||
def h1 = configurer.getHash(null, "hohoho")
|
def h1 = configurer.getHash(null, "hohoho")
|
||||||
@@ -119,7 +124,8 @@ class ConfiguredUpstreamsSpec extends Specification {
|
|||||||
Stub(UpstreamsConfig),
|
Stub(UpstreamsConfig),
|
||||||
callTargetsHolder,
|
callTargetsHolder,
|
||||||
Mock(ApplicationEventPublisher),
|
Mock(ApplicationEventPublisher),
|
||||||
Executors.newFixedThreadPool(1)
|
Executors.newFixedThreadPool(1),
|
||||||
|
ChainsConfig.default()
|
||||||
)
|
)
|
||||||
def methodsGroup = new UpstreamsConfig.MethodGroups(
|
def methodsGroup = new UpstreamsConfig.MethodGroups(
|
||||||
["filter"] as Set,
|
["filter"] as Set,
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
package io.emeraldpay.dshackle.test
|
package io.emeraldpay.dshackle.test
|
||||||
|
|
||||||
|
import io.emeraldpay.dshackle.config.ChainsConfig
|
||||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||||
import io.emeraldpay.dshackle.data.BlockContainer
|
import io.emeraldpay.dshackle.data.BlockContainer
|
||||||
import io.emeraldpay.dshackle.upstream.calls.AggregatedCallMethods
|
import io.emeraldpay.dshackle.upstream.calls.AggregatedCallMethods
|
||||||
@@ -73,7 +73,8 @@ class EthereumPosRpcUpstreamMock extends EthereumPosRpcUpstream {
|
|||||||
UpstreamsConfig.UpstreamRole.PRIMARY,
|
UpstreamsConfig.UpstreamRole.PRIMARY,
|
||||||
methods,
|
methods,
|
||||||
new QuorumForLabels.QuorumItem(1, UpstreamsConfig.Labels.fromMap(labels)),
|
new QuorumForLabels.QuorumItem(1, UpstreamsConfig.Labels.fromMap(labels)),
|
||||||
new ConnectorFactoryMock(api, new EthereumHeadMock()))
|
new ConnectorFactoryMock(api, new EthereumHeadMock()),
|
||||||
|
ChainsConfig.ChainConfig.default())
|
||||||
this.ethereumHeadMock = this.getHead() as EthereumHeadMock
|
this.ethereumHeadMock = this.getHead() as EthereumHeadMock
|
||||||
setLag(0)
|
setLag(0)
|
||||||
setStatus(UpstreamAvailability.OK)
|
setStatus(UpstreamAvailability.OK)
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
package io.emeraldpay.dshackle.test
|
package io.emeraldpay.dshackle.test
|
||||||
|
|
||||||
|
import io.emeraldpay.dshackle.config.ChainsConfig
|
||||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||||
import io.emeraldpay.dshackle.data.BlockContainer
|
import io.emeraldpay.dshackle.data.BlockContainer
|
||||||
import io.emeraldpay.dshackle.upstream.calls.AggregatedCallMethods
|
import io.emeraldpay.dshackle.upstream.calls.AggregatedCallMethods
|
||||||
@@ -65,7 +65,8 @@ class EthereumRpcUpstreamMock extends EthereumRpcUpstream {
|
|||||||
UpstreamsConfig.UpstreamRole.PRIMARY,
|
UpstreamsConfig.UpstreamRole.PRIMARY,
|
||||||
methods,
|
methods,
|
||||||
new QuorumForLabels.QuorumItem(1, new UpstreamsConfig.Labels()),
|
new QuorumForLabels.QuorumItem(1, new UpstreamsConfig.Labels()),
|
||||||
new ConnectorFactoryMock(api, new EthereumHeadMock()))
|
new ConnectorFactoryMock(api, new EthereumHeadMock()),
|
||||||
|
ChainsConfig.ChainConfig.default())
|
||||||
this.ethereumHeadMock = this.getHead() as EthereumHeadMock
|
this.ethereumHeadMock = this.getHead() as EthereumHeadMock
|
||||||
setLag(0)
|
setLag(0)
|
||||||
setStatus(UpstreamAvailability.OK)
|
setStatus(UpstreamAvailability.OK)
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
package io.emeraldpay.dshackle.upstream
|
package io.emeraldpay.dshackle.upstream
|
||||||
|
|
||||||
|
import io.emeraldpay.dshackle.config.ChainsConfig
|
||||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||||
import io.emeraldpay.dshackle.startup.QuorumForLabels
|
import io.emeraldpay.dshackle.startup.QuorumForLabels
|
||||||
import io.emeraldpay.dshackle.test.EthereumApiStub
|
import io.emeraldpay.dshackle.test.EthereumApiStub
|
||||||
@@ -57,7 +58,8 @@ class FilteredApisSpec extends Specification {
|
|||||||
UpstreamsConfig.UpstreamRole.PRIMARY,
|
UpstreamsConfig.UpstreamRole.PRIMARY,
|
||||||
ethereumTargets,
|
ethereumTargets,
|
||||||
new QuorumForLabels.QuorumItem(1, UpstreamsConfig.Labels.fromMap(it)),
|
new QuorumForLabels.QuorumItem(1, UpstreamsConfig.Labels.fromMap(it)),
|
||||||
connectorFactory
|
connectorFactory,
|
||||||
|
ChainsConfig.ChainConfig.default()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
def matcher = new Selector.LabelMatcher("test", ["foo"])
|
def matcher = new Selector.LabelMatcher("test", ["foo"])
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import io.emeraldpay.api.proto.BlockchainGrpc
|
|||||||
import io.emeraldpay.api.proto.BlockchainOuterClass
|
import io.emeraldpay.api.proto.BlockchainOuterClass
|
||||||
import io.emeraldpay.api.proto.Common
|
import io.emeraldpay.api.proto.Common
|
||||||
import io.emeraldpay.dshackle.Global
|
import io.emeraldpay.dshackle.Global
|
||||||
|
import io.emeraldpay.dshackle.config.ChainsConfig
|
||||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||||
import io.emeraldpay.dshackle.data.BlockId
|
import io.emeraldpay.dshackle.data.BlockId
|
||||||
import io.emeraldpay.dshackle.test.MockGrpcServer
|
import io.emeraldpay.dshackle.test.MockGrpcServer
|
||||||
@@ -83,7 +84,7 @@ class EthereumGrpcUpstreamSpec extends Specification {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
def upstream = new EthereumGrpcUpstream("test", hash, UpstreamsConfig.UpstreamRole.PRIMARY, chain, client, new JsonRpcGrpcClient(client, chain, metrics), null)
|
def upstream = new EthereumGrpcUpstream("test", hash, UpstreamsConfig.UpstreamRole.PRIMARY, chain, client, new JsonRpcGrpcClient(client, chain, metrics), null, ChainsConfig.ChainConfig.default())
|
||||||
upstream.setLag(0)
|
upstream.setLag(0)
|
||||||
upstream.update(BlockchainOuterClass.DescribeChain.newBuilder()
|
upstream.update(BlockchainOuterClass.DescribeChain.newBuilder()
|
||||||
.setStatus(BlockchainOuterClass.ChainStatus.newBuilder().setQuorum(1).setAvailabilityValue(UpstreamAvailability.OK.grpcId))
|
.setStatus(BlockchainOuterClass.ChainStatus.newBuilder().setQuorum(1).setAvailabilityValue(UpstreamAvailability.OK.grpcId))
|
||||||
@@ -141,7 +142,7 @@ class EthereumGrpcUpstreamSpec extends Specification {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
def upstream = new EthereumGrpcUpstream("test", hash, UpstreamsConfig.UpstreamRole.PRIMARY, Chain.ETHEREUM, client, new JsonRpcGrpcClient(client, Chain.ETHEREUM, metrics), null)
|
def upstream = new EthereumGrpcUpstream("test", hash, UpstreamsConfig.UpstreamRole.PRIMARY, Chain.ETHEREUM, client, new JsonRpcGrpcClient(client, Chain.ETHEREUM, metrics), null, ChainsConfig.ChainConfig.default())
|
||||||
upstream.setLag(0)
|
upstream.setLag(0)
|
||||||
upstream.update(BlockchainOuterClass.DescribeChain.newBuilder()
|
upstream.update(BlockchainOuterClass.DescribeChain.newBuilder()
|
||||||
.setStatus(BlockchainOuterClass.ChainStatus.newBuilder().setQuorum(1).setAvailabilityValue(UpstreamAvailability.OK.grpcId))
|
.setStatus(BlockchainOuterClass.ChainStatus.newBuilder().setQuorum(1).setAvailabilityValue(UpstreamAvailability.OK.grpcId))
|
||||||
@@ -203,7 +204,7 @@ class EthereumGrpcUpstreamSpec extends Specification {
|
|||||||
finished.complete(true)
|
finished.complete(true)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
def upstream = new EthereumGrpcUpstream("test", hash, UpstreamsConfig.UpstreamRole.PRIMARY, chain, client, new JsonRpcGrpcClient(client, chain, metrics), null)
|
def upstream = new EthereumGrpcUpstream("test", hash, UpstreamsConfig.UpstreamRole.PRIMARY, chain, client, new JsonRpcGrpcClient(client, chain, metrics), null, ChainsConfig.ChainConfig.default())
|
||||||
upstream.setLag(0)
|
upstream.setLag(0)
|
||||||
upstream.update(BlockchainOuterClass.DescribeChain.newBuilder()
|
upstream.update(BlockchainOuterClass.DescribeChain.newBuilder()
|
||||||
.setStatus(BlockchainOuterClass.ChainStatus.newBuilder().setQuorum(1).setAvailabilityValue(UpstreamAvailability.OK.grpcId))
|
.setStatus(BlockchainOuterClass.ChainStatus.newBuilder().setQuorum(1).setAvailabilityValue(UpstreamAvailability.OK.grpcId))
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package io.emeraldpay.dshackle.config
|
||||||
|
|
||||||
|
import io.emeraldpay.dshackle.Chain
|
||||||
|
import org.junit.jupiter.api.Assertions.*
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
|
internal class ChainsConfigTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun patch() {
|
||||||
|
val orig = ChainsConfig(
|
||||||
|
mapOf(
|
||||||
|
Chain.BITCOIN to ChainsConfig.RawChainConfig(0, 0),
|
||||||
|
Chain.ETHEREUM to ChainsConfig.RawChainConfig(1, 2),
|
||||||
|
Chain.POLYGON to ChainsConfig.RawChainConfig(3, 4)
|
||||||
|
),
|
||||||
|
ChainsConfig.RawChainConfig(1, 2)
|
||||||
|
)
|
||||||
|
|
||||||
|
val patch = ChainsConfig(
|
||||||
|
mapOf(
|
||||||
|
Chain.BITCOIN to ChainsConfig.RawChainConfig(null, 10000),
|
||||||
|
Chain.POLYGON to ChainsConfig.RawChainConfig(10, 11),
|
||||||
|
Chain.ARBITRUM to ChainsConfig.RawChainConfig(999, 999)
|
||||||
|
),
|
||||||
|
ChainsConfig.RawChainConfig(100, null)
|
||||||
|
)
|
||||||
|
|
||||||
|
val res = orig.patch(patch)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
ChainsConfig(
|
||||||
|
mapOf(
|
||||||
|
Chain.BITCOIN to ChainsConfig.RawChainConfig(0, 10000),
|
||||||
|
Chain.ETHEREUM to ChainsConfig.RawChainConfig(1, 2),
|
||||||
|
Chain.POLYGON to ChainsConfig.RawChainConfig(10, 11),
|
||||||
|
Chain.ARBITRUM to ChainsConfig.RawChainConfig(999, 999)
|
||||||
|
),
|
||||||
|
ChainsConfig.RawChainConfig(100, 2)
|
||||||
|
),
|
||||||
|
res
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/test/resources/configs/chains-basic.yaml
Normal file
18
src/test/resources/configs/chains-basic.yaml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
version: v1
|
||||||
|
|
||||||
|
chain-settings:
|
||||||
|
default:
|
||||||
|
lags:
|
||||||
|
syncing: 6
|
||||||
|
lagging: 1
|
||||||
|
chains:
|
||||||
|
- id: eth
|
||||||
|
lags:
|
||||||
|
syncing: 6
|
||||||
|
lagging: 1
|
||||||
|
- id: optimism
|
||||||
|
lags:
|
||||||
|
lagging: 3
|
||||||
|
- id: sepolia
|
||||||
|
lags:
|
||||||
|
syncing: 10
|
||||||
Reference in New Issue
Block a user