diff --git a/build.gradle b/build.gradle index 5aa8a838..8f94d3c6 100644 --- a/build.gradle +++ b/build.gradle @@ -23,7 +23,7 @@ plugins { group = 'io.emeraldpay.dshackle' -version = '0.1-SNAPSHOT' +version = '0.2-SNAPSHOT' targetCompatibility = '1.8' sourceCompatibility = '1.8' diff --git a/src/main/java/io/emeraldpay/dshackle/config/UpstreamsConfig.java b/src/main/java/io/emeraldpay/dshackle/config/UpstreamsConfig.java deleted file mode 100644 index c0987e7a..00000000 --- a/src/main/java/io/emeraldpay/dshackle/config/UpstreamsConfig.java +++ /dev/null @@ -1,448 +0,0 @@ -package io.emeraldpay.dshackle.config; - -import org.yaml.snakeyaml.TypeDescription; -import org.yaml.snakeyaml.introspector.GenericProperty; -import org.yaml.snakeyaml.introspector.MethodProperty; -import org.yaml.snakeyaml.introspector.Property; -import org.yaml.snakeyaml.introspector.PropertySubstitute; -import org.yaml.snakeyaml.nodes.MappingNode; -import org.yaml.snakeyaml.nodes.Node; -import org.yaml.snakeyaml.nodes.ScalarNode; - -import javax.annotation.Nullable; -import java.beans.IntrospectionException; -import java.beans.PropertyDescriptor; -import java.lang.annotation.Annotation; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Type; -import java.net.URI; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Optional; - -public class UpstreamsConfig { - - private String version; - private List defaultOptions; - private List upstreams; - - public String getVersion() { - return version; - } - - public void setVersion(String version) { - this.version = version; - } - - public List getDefaultOptions() { - return defaultOptions; - } - - public void setDefaultOptions(List defaultOptions) { - this.defaultOptions = defaultOptions; - } - - public List getUpstreams() { - return upstreams; - } - - public void setUpstreams(List upstreams) { - this.upstreams = upstreams; - } - - public static class Options { - private Boolean disableSyncing; - private Integer minPeers; - private Integer quorum; - - public Boolean getDisableSyncing() { - return disableSyncing; - } - - public void setDisableSyncing(Boolean disableSyncing) { - this.disableSyncing = disableSyncing; - } - - public Integer getMinPeers() { - return minPeers; - } - - public void setMinPeers(Integer minPeers) { - if (minPeers < 0) { - throw new IllegalArgumentException("minPeers must be positive number"); - } - this.minPeers = minPeers; - } - - public Integer getQuorum() { - return quorum; - } - - public void setQuorum(Integer quorum) { - if (quorum < 0) { - throw new IllegalArgumentException("quorum must be positive number"); - } - this.quorum = quorum; - } - - public Options merge(Options additional) { - if (additional == null) { - return this; - } - Options copy = new Options(); - copy.setDisableSyncing(this.disableSyncing != null ? this.disableSyncing : additional.disableSyncing); - copy.setMinPeers(this.minPeers != null ? this.minPeers : additional.minPeers); - copy.setQuorum(this.quorum != null ? this.quorum : additional.quorum); - return copy; - } - - public static Options getDefaults() { - Options options = new Options(); - options.setDisableSyncing(true); - options.setMinPeers(1); - options.setQuorum(1); - return options; - } - - } - - public static class OptionsYaml extends TypeDescription { - - public OptionsYaml() { - super(Options.class); - super.substituteProperty(new PropertySubstitute("disable-syncing", Boolean.class, - "getDisableSyncing", "setDisableSyncing")); - super.substituteProperty(new PropertySubstitute("min-peers", Integer.class, - "getMinPeers", "setMinPeers")); - } - } - - - public static class DefaultOptions extends Options { - private List chains; - private Options options; - - public List getChains() { - return chains; - } - - public void setChains(List chains) { - this.chains = chains; - } - - public Options getOptions() { - return options; - } - - public void setOptions(Options options) { - this.options = options; - } - } - - public static class Upstream { - private String id; - private String chain; - - @Nullable - private String provider; - private List endpoints = Collections.emptyList(); - private Options options; - private boolean enabled = true; - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getChain() { - return chain; - } - - public void setChain(String chain) { - this.chain = chain; - } - - @Nullable - public String getProvider() { - return provider; - } - - public void setProvider(@Nullable String provider) { - this.provider = provider; - } - - public List getEndpoints() { - return endpoints; - } - - public void setEndpoints(List endpoints) { - this.endpoints = endpoints; - } - - @Nullable - public Options getOptions() { - return options; - } - - public void setOptions(Options options) { - this.options = options; - } - - public boolean isEnabled() { - return enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - } - - public static class Endpoint { - private EndpointType type; - private URI url; - private String host; - private int port; - @Nullable - private Auth auth; - private Boolean enabled = true; - @Nullable - private URI origin; - - public EndpointType getType() { - return type; - } - - public void setType(EndpointType type) { - this.type = type; - } - - public URI getUrl() { - return url; - } - - public void setUrl(URI url) { - this.url = url; - } - - @Nullable - public Auth getAuth() { - return auth; - } - - public void setAuth(@Nullable Auth auth) { - this.auth = auth; - } - - public Boolean getEnabled() { - return enabled; - } - - public void setEnabled(Boolean enabled) { - this.enabled = enabled; - } - - @Nullable - public URI getOrigin() { - return origin; - } - - public void setOrigin(@Nullable URI origin) { - this.origin = origin; - } - - public String getHost() { - return host; - } - - public void setHost(String host) { - this.host = host; - } - - public int getPort() { - return port; - } - - public void setPort(int port) { - this.port = port; - } - } - - public static class Auth { - private String type; - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - } - - public static interface WithKey { - public String getKey(); - public void setKey(String key); - } - - public static class BasicAuth extends Auth implements WithKey { - private String key; - - public String getKey() { - return key; - } - - public void setKey(String key) { - this.key = key; - } - } - - public static class TlsAuth extends Auth implements WithKey { - private String ca; - private String certificate; - private String key; - - public String getCa() { - return ca; - } - - public void setCa(String ca) { - this.ca = ca; - } - - public String getCertificate() { - return certificate; - } - - public void setCertificate(String certificate) { - this.certificate = certificate; - } - - public String getKey() { - return key; - } - - public void setKey(String key) { - this.key = key; - } - } - - public static class AuthYaml extends TypeDescription { - - public AuthYaml() { - super(Auth.class); - } - - public Class getImpl() { - try { - Field f = TypeDescription.class.getDeclaredField("impl"); - f.setAccessible(true); - return (Class) f.get(this); - } catch (NoSuchFieldException | IllegalAccessException e) { - e.printStackTrace(); - } - return null; - } - - @Override - public Property getProperty(String name) { - if ("key".equals(name)) { - try { - return new MethodProperty(new PropertyDescriptor("key", WithKey.class, "getKey", "setKey")); - } catch (IntrospectionException e) { - e.printStackTrace(); - } - } - if ("ca".equals(name)) { - try { - return new MethodProperty(new PropertyDescriptor("ca", TlsAuth.class, "getCa", "setCa")); - } catch (IntrospectionException e) { - e.printStackTrace(); - } - } - if ("certificate".equals(name)) { - try { - return new MethodProperty(new PropertyDescriptor("certificate", TlsAuth.class, "getCertificate", "setCertificate")); - } catch (IntrospectionException e) { - e.printStackTrace(); - } - } - return super.getProperty(name); - } - - private Optional getValue(MappingNode mappingNode, String key) { - return mappingNode.getValue() - .stream() - .filter((n) -> n.getKeyNode() instanceof ScalarNode && n.getValueNode() instanceof ScalarNode) - .filter((n) -> { - ScalarNode sn = (ScalarNode)n.getKeyNode(); - return "type".equals(sn.getValue()); - }) - .map((n) -> (ScalarNode)n.getValueNode()) - .findFirst(); - } - - @Override - public Object newInstance(Node node) { - if (node instanceof MappingNode) { - MappingNode mappingNode = (MappingNode)node; - Optional type = getValue(mappingNode, "type"); - if (type.isPresent()) { - if ("basic".equals(type.get().getValue())) { - return new BasicAuth(); - } else if ("tls".equals(type.get().getValue())) { - return new TlsAuth(); - } else { - throw new IllegalArgumentException("Unsupported auth type: " + type.get().getValue()); - } - } else { - throw new IllegalArgumentException("Auth type is not set"); - } - } - throw new IllegalArgumentException("Auth is invalid"); - } - } - - public static enum EndpointType { - JSON_RPC("json-rpc"), - WEBSOCKET("ws", "websocket"), - DSHACKLE("dshackle"), - UNKNOWN("unknown"); - - private final String[] code; - - EndpointType(String ... code) { - this.code = code; - Arrays.sort(this.code); - } - - public static EndpointType byName(String code) { - code = code.toLowerCase(); - for (EndpointType t: EndpointType.values()) { - if (Arrays.binarySearch(t.code, code) >= 0) { - return t; - } - } - return UNKNOWN; - } - } - - public static class EndpointTypeYaml extends TypeDescription { - - public EndpointTypeYaml() { - super(EndpointType.class); - } - - @Override - public Object newInstance(Node node) { - if (node instanceof ScalarNode) { - return EndpointType.byName(((ScalarNode)node).getValue()); - } - throw new IllegalArgumentException("Invalid type: " + node.getClass()); - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/io/emeraldpay/dshackle/config/UpstreamsConfig.kt b/src/main/kotlin/io/emeraldpay/dshackle/config/UpstreamsConfig.kt new file mode 100644 index 00000000..c5290b4e --- /dev/null +++ b/src/main/kotlin/io/emeraldpay/dshackle/config/UpstreamsConfig.kt @@ -0,0 +1,120 @@ +package io.emeraldpay.dshackle.config + +import java.net.URI +import java.util.* +import kotlin.collections.ArrayList + +class UpstreamsConfig { + var version: String? = null + var defaultOptions: MutableList = ArrayList() + var upstreams: MutableList> = ArrayList>() + + open class Options { + @Deprecated("remove it") + var quorum: Int = 1 + var disableSyncing: Boolean? = null + var minPeers: Int? = 1 + set(minPeers) { + if (minPeers != null && minPeers < 0) { + throw IllegalArgumentException("minPeers must be positive number") + } + field = minPeers + } + + fun merge(additional: Options?): Options { + if (additional == null) { + return this + } + val copy = Options() + copy.disableSyncing = if (this.disableSyncing != null) this.disableSyncing else additional.disableSyncing + copy.minPeers = if (this.minPeers != null) this.minPeers else additional.minPeers + return copy + } + + companion object { + fun getDefaults(): Options { + val options = Options() + options.disableSyncing = true + options.minPeers = 1 + return options + } + } + + } + + class DefaultOptions : Options() { + var chains: List? = null + var options: Options? = null + } + + class Upstream { + var id: String? = null + var chain: String? = null + var provider: String? = null + var options: Options? = null + var isEnabled = true + var connection: T? = null + } + + open class UpstreamConnection + + class GrpcConnection : UpstreamConnection() { + var host: String? = null + var port: Int = 0 + var auth: TlsAuth? = null + } + + class EthereumConnection : UpstreamConnection() { + var rpc: HttpEndpoint? = null + var ws: WsEndpoint? = null + } + + class HttpEndpoint(val url: URI) { + var auth: Auth? = null + } + + class WsEndpoint(val url: URI) { + var origin: URI? = null + } + + open class Auth { + var type: String? = null + } + + class BasicAuth : Auth() { + var key: String? = null + } + + class TlsAuth : Auth() { + var ca: String? = null + var certificate: String? = null + var key: String? = null + } + + enum class UpstreamType private constructor(vararg code: String) { + ETHEREUM_JSON_RPC("ethereum"), + DSHACKLE("dshackle", "grpc"), + UNKNOWN("unknown"); + + private val code: Array + + init { + this.code = code as Array + Arrays.sort(this.code) + } + + companion object { + + fun byName(code: String): UpstreamType { + var code = code + code = code.toLowerCase() + for (t in UpstreamType.values()) { + if (Arrays.binarySearch(t.code, code) >= 0) { + return t + } + } + return UNKNOWN + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/io/emeraldpay/dshackle/config/UpstreamsConfigReader.kt b/src/main/kotlin/io/emeraldpay/dshackle/config/UpstreamsConfigReader.kt index 0fa3738d..bd0155ab 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/config/UpstreamsConfigReader.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/config/UpstreamsConfigReader.kt @@ -1,17 +1,198 @@ package io.emeraldpay.dshackle.config +import org.slf4j.LoggerFactory import org.yaml.snakeyaml.Yaml +import org.yaml.snakeyaml.nodes.CollectionNode +import org.yaml.snakeyaml.nodes.MappingNode +import org.yaml.snakeyaml.nodes.Node +import org.yaml.snakeyaml.nodes.ScalarNode import java.io.InputStream +import java.io.InputStreamReader +import java.lang.IllegalArgumentException +import java.net.URI class UpstreamsConfigReader { + private val log = LoggerFactory.getLogger(UpstreamsConfigReader::class.java) + fun read(input: InputStream): UpstreamsConfig { val yaml = Yaml() - yaml.addTypeDescription(UpstreamsConfig.EndpointTypeYaml()) - yaml.addTypeDescription(UpstreamsConfig.OptionsYaml()) - yaml.addTypeDescription(UpstreamsConfig.AuthYaml()) - return yaml.loadAs(input, UpstreamsConfig::class.java) + val configNode = asMappingNode(yaml.compose(InputStreamReader(input))) + + val config = UpstreamsConfig() + config.version = getValueAsString(configNode, "version") + + getList(configNode, "defaultOptions")?.value?.forEach { opts -> + val defaultOptions = UpstreamsConfig.DefaultOptions() + config.defaultOptions.add(defaultOptions) + defaultOptions.chains = getListOfString(opts, "chains") + val options = UpstreamsConfig.Options() + defaultOptions.options = options + getMapping(opts, "options")?.let { values -> + getValueAsBool(values, "disable-syncing")?.let { + options.disableSyncing = it + } + getValueAsInt(values, "min-peers")?.let { + options.minPeers = it + } + } + } + + config.upstreams = ArrayList>() + getList(configNode, "upstreams")?.value?.forEach { upNode -> + val connNode = getMapping(upNode, "connection") + if (hasAny(connNode, "ethereum")) { + val connConfigNode = getMapping(connNode, "ethereum")!! + val upstream = UpstreamsConfig.Upstream() + upstream.id = getValueAsString(upNode, "id") + upstream.provider = getValueAsString(upNode, "provider") + upstream.chain = getValueAsString(upNode, "chain") + config.upstreams.add(upstream) + val connection = UpstreamsConfig.EthereumConnection() + upstream.connection = connection + getMapping(connConfigNode, "rpc")?.let { node -> + getValueAsString(node, "url")?.let { url -> + val http = UpstreamsConfig.HttpEndpoint(URI(url)) + connection.rpc = http + http.auth = readAuth(getMapping(node, "auth")) + } + } + getMapping(connConfigNode, "ws")?.let { node -> + getValueAsString(node, "url")?.let { url -> + val ws = UpstreamsConfig.WsEndpoint(URI(url)) + connection.ws = ws + getValueAsString(node, "origin")?.let { origin -> + ws.origin = URI(origin) + } +// ws.auth = readAuth(getMapping(node, "auth")) + } + } + } else if (hasAny(connNode, "grpc")) { + val connConfigNode = getMapping(connNode, "grpc")!! + val upstream = UpstreamsConfig.Upstream() + upstream.id = getValueAsString(upNode, "id") + upstream.provider = getValueAsString(upNode, "provider") + config.upstreams.add(upstream) + val connection = UpstreamsConfig.GrpcConnection() + upstream.connection = connection + getValueAsString(connConfigNode, "host")?.let { + connection.host = it + } + getValueAsInt(connConfigNode, "port")?.let { + connection.port = it + } + connection.auth = readAuth(getMapping(connConfigNode, "auth")) as UpstreamsConfig.TlsAuth? + } + } + + return config } + private fun readAuth(authNode: MappingNode?): UpstreamsConfig.Auth? { + return getValueAsString(authNode, "type")?.let { + return when (it) { + "tls" -> { + val auth = UpstreamsConfig.TlsAuth() + auth.ca = getValueAsString(authNode, "ca") + auth.certificate = getValueAsString(authNode, "certificate") + auth.key = getValueAsString(authNode, "key") + auth + } + "basic" -> { + val auth = UpstreamsConfig.BasicAuth() + auth.key = getValueAsString(authNode, "key") + auth + } + else -> { + log.warn("Invalid Auth type: $it") + null + } + } + } + } + private fun hasAny(mappingNode: MappingNode?, key: String): Boolean { + if (mappingNode == null) { + return false + } + return mappingNode.value + .stream() + .filter { n -> n.keyNode is ScalarNode } + .filter { n -> + val sn = n.keyNode as ScalarNode + key == sn.value + }.count() > 0 + } + + private fun getValue(mappingNode: MappingNode?, key: String, type: Class): T? { + if (mappingNode == null) { + return null + } + return mappingNode.value + .stream() + .filter { n -> n.keyNode is ScalarNode && type.isAssignableFrom(n.valueNode.javaClass) } + .filter { n -> + val sn = n.keyNode as ScalarNode + key == sn.value + } + .map { n -> n.valueNode as T } + .findFirst().let { + if (it.isPresent) { + it.get() + } else { + null + } + } + } + + private fun getMapping(mappingNode: MappingNode?, key: String): MappingNode? { + return getValue(mappingNode, key, MappingNode::class.java) + } + + private fun getValue(mappingNode: MappingNode?, key: String): ScalarNode? { + return getValue(mappingNode, key, ScalarNode::class.java) + } + + private fun getList(mappingNode: MappingNode?, key: String): CollectionNode? { + return getValue(mappingNode, key, CollectionNode::class.java) as CollectionNode + } + + private fun getListOfString(mappingNode: MappingNode?, key: String): List? { + return getList(mappingNode, key)?.value + ?.map { it.value } + } + + private fun getValueAsString(mappingNode: MappingNode?, key: String): String? { + return getValue(mappingNode, key)?.let { + return@let it.value + } + } + + private fun getValueAsInt(mappingNode: MappingNode?, key: String): Int? { + return getValue(mappingNode, key)?.let { + return@let if (it.isPlain) { + it.value.toIntOrNull() + } else { + null + } + } + } + + private fun getValueAsBool(mappingNode: MappingNode?, key: String): Boolean? { + return getValue(mappingNode, key)?.let { + return@let if (it.isPlain) { + it.value?.toLowerCase() == "true" + } else { + null + } + } + } + + private fun asMappingNode(node: Node): MappingNode { + return if (MappingNode::class.java.isAssignableFrom(node.javaClass)) { + node as MappingNode + } else { + throw IllegalArgumentException("Not a map") + } + } } \ No newline at end of file diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/ConfiguredUpstreams.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/ConfiguredUpstreams.kt index a28ed540..8aed8237 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/ConfiguredUpstreams.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/ConfiguredUpstreams.kt @@ -41,10 +41,14 @@ open class ConfiguredUpstreams( val config = readConfig() val defaultOptions = buildDefaultOptions(config) config.upstreams.forEach { up -> + val options = (up.options ?: UpstreamsConfig.Options()) + .merge(UpstreamsConfig.Options.getDefaults()) + if (up.provider == "dshackle") { - buildGrpcUpstream(up) + buildGrpcUpstream(up.connection as UpstreamsConfig.GrpcConnection, options) } else { - buildEthereumUpstream(up, defaultOptions) + val chain = chainNames[up.chain] ?: return + buildEthereumUpstream(up.connection as UpstreamsConfig.EthereumConnection, chain, options) } } } @@ -69,7 +73,7 @@ open class ConfiguredUpstreams( private fun buildDefaultOptions(config: UpstreamsConfig): HashMap { val defaultOptions = HashMap() config.defaultOptions.forEach { df -> - df.chains.forEach { chainName -> + df.chains?.forEach { chainName -> chainNames[chainName]?.let { chain -> var current = defaultOptions[chain] if (current == null) { @@ -77,56 +81,45 @@ open class ConfiguredUpstreams( } else { current = current.merge(df.options) } - defaultOptions[chain] = current + defaultOptions[chain] = current!! } } } return defaultOptions } - private fun buildEthereumUpstream(up: UpstreamsConfig.Upstream, - defaultOptions: HashMap) { - val chain = chainNames[up.chain] ?: return + private fun buildEthereumUpstream(up: UpstreamsConfig.EthereumConnection, + chain: Chain, + options: UpstreamsConfig.Options) { var rpcApi: EthereumApi? = null var wsApi: EthereumWs? = null val urls = ArrayList() - up.endpoints.forEach { endpoint -> - if (endpoint.type == UpstreamsConfig.EndpointType.JSON_RPC) { - rpcApi = EthereumApi( - DefaultRpcClient(DefaultRpcTransport(endpoint.url)), - objectMapper, - chain - ) - } - if (endpoint.type == UpstreamsConfig.EndpointType.WEBSOCKET) { - wsApi = EthereumWs( - endpoint.url, - endpoint.origin ?: URI("http://localhost") - ) - wsApi!!.connect() - } + up.rpc?.let { endpoint -> + rpcApi = EthereumApi( + DefaultRpcClient(DefaultRpcTransport(endpoint.url)), + objectMapper, + chain + ) + urls.add(endpoint.url) + } + up.ws?.let { endpoint -> + wsApi = EthereumWs( + endpoint.url, + endpoint.origin ?: URI("http://localhost") + ) + wsApi!!.connect() urls.add(endpoint.url) } - val options = (up.options ?: UpstreamsConfig.Options()) - .merge(defaultOptions[chain]) - .merge(UpstreamsConfig.Options.getDefaults()) if (rpcApi != null) { log.info("Using ${chain.chainName} upstream, at ${urls.joinToString()}") getOrCreateUpstream(chain).addUpstream(EthereumUpstream(chain, rpcApi!!, wsApi, options)) } } - private fun buildGrpcUpstream(up: UpstreamsConfig.Upstream) { - if (up.endpoints.size == 0) { - return - } - val options = (up.options ?: UpstreamsConfig.Options()) - .merge(UpstreamsConfig.Options.getDefaults()) - - val endpoint = up.endpoints.first() - if (endpoint.type == UpstreamsConfig.EndpointType.DSHACKLE) { + private fun buildGrpcUpstream(up: UpstreamsConfig.GrpcConnection, options: UpstreamsConfig.Options) { + val endpoint = up val ds = GrpcUpstreams( - endpoint.host, + endpoint.host!!, endpoint.port ?: 443, objectMapper, options @@ -140,7 +133,6 @@ open class ConfiguredUpstreams( log.info("Subscribed to $it through gRPC at ${endpoint.host}:${endpoint.port}") getOrCreateUpstream(it).addUpstream(ds.getOrCreate(it)) } - } } override fun getUpstream(chain: Chain): AggregatedUpstreams? { diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/UpstreamValidator.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/UpstreamValidator.kt index 47f52422..11fe4ffc 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/UpstreamValidator.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/UpstreamValidator.kt @@ -21,7 +21,7 @@ class UpstreamValidator( if (syncing.get().isSyncing) { return UpstreamAvailability.SYNCING } - if (peerCount.get() < options.minPeers) { + if (options.minPeers != null && peerCount.get() < options.minPeers!!) { return UpstreamAvailability.IMMATURE } return UpstreamAvailability.OK diff --git a/src/test/groovy/io/emeraldpay/dshackle/config/UpstreamsConfigReaderSpec.groovy b/src/test/groovy/io/emeraldpay/dshackle/config/UpstreamsConfigReaderSpec.groovy index ea79b91b..0fa80bef 100644 --- a/src/test/groovy/io/emeraldpay/dshackle/config/UpstreamsConfigReaderSpec.groovy +++ b/src/test/groovy/io/emeraldpay/dshackle/config/UpstreamsConfigReaderSpec.groovy @@ -18,7 +18,6 @@ class UpstreamsConfigReaderSpec extends Specification { size() == 1 with(get(0)) { chains == ["ethereum"] - options.quorum == 1 options.minPeers == 3 options.disableSyncing } @@ -28,28 +27,26 @@ class UpstreamsConfigReaderSpec extends Specification { id == "local" chain == "ethereum" provider == "geth" - endpoints.size() == 2 - with(endpoints.get(0)) { - type == UpstreamsConfig.EndpointType.JSON_RPC - url == new URI("http://localhost:8545") - } - with(endpoints.get(1)) { - type == UpstreamsConfig.EndpointType.WEBSOCKET - url == new URI("ws://localhost:8546") + connection instanceof UpstreamsConfig.EthereumConnection + with((UpstreamsConfig.EthereumConnection)connection) { + rpc != null + rpc.url == new URI("http://localhost:8545") + ws != null + ws.url == new URI("ws://localhost:8546") } } with(act.upstreams.get(1)) { id == "infura" chain == "ethereum" provider == "infura" - endpoints.size() == 1 - with(endpoints.get(0)) { - type == UpstreamsConfig.EndpointType.JSON_RPC - url == new URI("https://mainnet.infura.io/v3/fa28c968191849c1aff541ad1d8511f2") - auth instanceof UpstreamsConfig.BasicAuth - with((UpstreamsConfig.BasicAuth)auth) { + connection instanceof UpstreamsConfig.EthereumConnection + with((UpstreamsConfig.EthereumConnection)connection) { + rpc.url == new URI("https://mainnet.infura.io/v3/fa28c968191849c1aff541ad1d8511f2") + rpc.auth instanceof UpstreamsConfig.BasicAuth + with((UpstreamsConfig.BasicAuth)rpc.auth) { key == "4fc258fe41a68149c199ad8f281f2015" } + ws == null } } @@ -66,11 +63,9 @@ class UpstreamsConfigReaderSpec extends Specification { act.upstreams.size() == 1 with(act.upstreams.get(0)) { id == "remote" - chain == "auto" provider == "dshackle" - endpoints.size() == 1 - with(endpoints.get(0)) { - type == UpstreamsConfig.EndpointType.DSHACKLE + connection instanceof UpstreamsConfig.GrpcConnection + with((UpstreamsConfig.GrpcConnection)connection) { host == "10.2.0.15" auth instanceof UpstreamsConfig.TlsAuth with((UpstreamsConfig.TlsAuth)auth) { diff --git a/src/test/resources/upstreams-basic.yaml b/src/test/resources/upstreams-basic.yaml index bdf878d4..f7028cbe 100644 --- a/src/test/resources/upstreams-basic.yaml +++ b/src/test/resources/upstreams-basic.yaml @@ -6,24 +6,25 @@ defaultOptions: options: disable-syncing: true min-peers: 3 - quorum: 1 upstreams: - id: local chain: ethereum provider: geth - endpoints: - - type: json-rpc - url: "http://localhost:8545" - - type: ws - url: "ws://localhost:8546" - origin: "http://localhost" + connection: + ethereum: + rpc: + url: "http://localhost:8545" + ws: + url: "ws://localhost:8546" + origin: "http://localhost" - id: infura chain: ethereum provider: infura - endpoints: - - type: json-rpc - url: "https://mainnet.infura.io/v3/fa28c968191849c1aff541ad1d8511f2" - auth: - type: basic - key: 4fc258fe41a68149c199ad8f281f2015 \ No newline at end of file + connection: + ethereum: + rpc: + url: "https://mainnet.infura.io/v3/fa28c968191849c1aff541ad1d8511f2" + auth: + type: basic + key: 4fc258fe41a68149c199ad8f281f2015 \ No newline at end of file diff --git a/src/test/resources/upstreams-ds.yaml b/src/test/resources/upstreams-ds.yaml index a2d20445..cc2df79e 100644 --- a/src/test/resources/upstreams-ds.yaml +++ b/src/test/resources/upstreams-ds.yaml @@ -6,14 +6,12 @@ defaultOptions: options: disable-syncing: true min-peers: 3 - quorum: 1 upstreams: - id: remote - chain: auto provider: dshackle - endpoints: - - type: dshackle + connection: + grpc: host: "10.2.0.15" auth: type: tls