Files
dshackle/foundation/src/main/kotlin/org/drpc/chainsconfig/ChainsConfigReader.kt
Anton 772142e156 Check gas price (#494)
* add gas validation option

* gas price config for chains

* check gas price

* add tests

* fix txt

* make gas price dls

* fix config
2024-05-31 15:46:55 +03:00

127 lines
6.8 KiB
Kotlin

package io.emeraldpay.dshackle.config
import io.emeraldpay.dshackle.foundation.ChainOptions
import io.emeraldpay.dshackle.foundation.ChainOptionsReader
import io.emeraldpay.dshackle.foundation.YamlConfigReader
import org.yaml.snakeyaml.DumperOptions
import org.yaml.snakeyaml.nodes.MappingNode
import org.yaml.snakeyaml.nodes.NodeTuple
import org.yaml.snakeyaml.nodes.ScalarNode
import org.yaml.snakeyaml.nodes.Tag
import java.math.BigInteger
class ChainsConfigReader(
private val chainsOptionsReader: ChainOptionsReader,
) : YamlConfigReader<ChainsConfig>() {
private val defaultConfig = this::class.java.getResourceAsStream("/chains.yaml")!!
private fun readChains(input: MappingNode?): Map<Int, Pair<String, MappingNode>> {
return getMapping(input, "chain-settings")?.let { config ->
val default = getMapping(config, "default")
getList<MappingNode>(config, "protocols")?.let { protocols ->
protocols.value.fold(emptyMap()) { acc, protocol ->
val blockchain = getValueAsString(protocol, "id")
?: throw IllegalArgumentException("Blockchain id is not defined")
val type = getValueAsString(protocol, "type")
?: throw IllegalArgumentException("undefined type for $blockchain")
val settings = mergeMappingNode(default, getMapping(protocol, "settings"))
acc.plus(
getList<MappingNode>(protocol, "chains")?.let { chains ->
chains.value.map { chain ->
val chainSettings = mergeMappingNode(settings, getMapping(chain, "settings"))
val updatedChain = mergeMappingNode(
chain,
MappingNode(
chain.tag,
listOf(
NodeTuple(ScalarNode(Tag.STR, "settings", null, null, DumperOptions.ScalarStyle.LITERAL), chainSettings),
NodeTuple(
ScalarNode(Tag.STR, "blockchain", null, null, DumperOptions.ScalarStyle.LITERAL),
ScalarNode(Tag.STR, blockchain, null, null, DumperOptions.ScalarStyle.LITERAL),
),
NodeTuple(
ScalarNode(Tag.STR, "type", null, null, DumperOptions.ScalarStyle.LITERAL),
ScalarNode(Tag.STR, type, null, null, DumperOptions.ScalarStyle.LITERAL),
),
),
chain.flowStyle,
),
)
val grpcId = getValueAsInt(updatedChain, "grpcId")
?: throw IllegalArgumentException("grpcId for chain is not defined")
Pair(grpcId, Pair(blockchain, updatedChain!!))
}
} ?: listOf(),
)
}
}
} ?: emptyMap()
}
private fun parseChain(blockchain: String, node: MappingNode): ChainsConfig.ChainConfig {
val id = getValueAsString(node, "id")
?: throw IllegalArgumentException("undefined id for $blockchain")
val settings = getMapping(node, "settings") ?: throw IllegalArgumentException("undefined settings for $blockchain")
val lags = getMapping(settings, "lags")?.let { lagConfig ->
Pair(
getValueAsInt(lagConfig, "syncing")
?: throw IllegalArgumentException("undefined syncing for $blockchain"),
getValueAsInt(lagConfig, "lagging")
?: throw IllegalArgumentException("undefined lagging for $blockchain"),
)
} ?: throw IllegalArgumentException("undefined lags for $blockchain")
val expectedBlockTime = getValueAsDuration(settings, "expected-block-time")
?: throw IllegalArgumentException("undefined expected block time")
val validateContract = getValueAsString(node, "call-validate-contract")
val options = chainsOptionsReader.read(settings) ?: ChainOptions.PartialOptions()
val chainId = getValueAsString(node, "chain-id")
?: throw IllegalArgumentException("undefined chain id for $blockchain")
val code = getValueAsString(node, "code")
?: throw IllegalArgumentException("undefined code for $blockchain")
val grpcId = getValueAsInt(node, "grpcId")
?: throw IllegalArgumentException("undefined code for $blockchain")
val netVersion = getValueAsLong(node, "net-version")?.toBigInteger() ?: BigInteger(chainId.drop(2), 16)
val shortNames = getListOfString(node, "short-names")
?: throw IllegalArgumentException("undefined shortnames for $blockchain")
val type = getValueAsString(node, "type")
?: throw IllegalArgumentException("undefined type for $blockchain")
val gasPriceCondition = getValueAsString(node, "gas-price-condition")
return ChainsConfig.ChainConfig(
expectedBlockTime = expectedBlockTime,
syncingLagSize = lags.first,
laggingLagSize = lags.second,
options = options,
callLimitContract = validateContract,
chainId = chainId,
code = code,
grpcId = grpcId,
netVersion = netVersion,
shortNames = shortNames,
id = id,
blockchain = blockchain,
type = type,
gasPriceCondition = gasPriceCondition?.let { ChainsConfig.GasPriceCondition(gasPriceCondition) },
)
}
override fun read(input: MappingNode?): ChainsConfig {
val default = readChains(readNode(defaultConfig))
val current = readChains(input)
val chains = default.keys.toSet().plus(current.keys).map {
val defChain = default[it]
val curChain = current[it]
when {
curChain == null && defChain != null -> parseChain(defChain.first, defChain.second)
curChain != null && defChain == null -> parseChain(curChain.first, curChain.second)
curChain != null && defChain != null -> {
val merged = mergeMappingNode(defChain.second, curChain.second)
parseChain(defChain.first, merged!!)
}
else -> ChainsConfig.ChainConfig.default()
}
}
return ChainsConfig(chains)
}
}