From 35d311ef1b1ee7983909eef5076fd286f3f12a4e Mon Sep 17 00:00:00 2001 From: KirillPamPam Date: Thu, 16 Jan 2025 14:02:14 +0400 Subject: [PATCH] Remove oracle (#620) --- build.gradle | 8 -- .../kotlin/io/emeraldpay/dshackle/Config.kt | 6 -- .../emeraldpay/dshackle/config/IndexConfig.kt | 21 ---- .../dshackle/config/IndexConfigReader.kt | 62 ------------ .../emeraldpay/dshackle/config/MainConfig.kt | 1 - .../dshackle/config/MainConfigReader.kt | 4 - .../config/context/MultistreamsConfig.kt | 11 --- .../config/context/SchedulersConfig.kt | 5 - .../configure/BitcoinUpstreamCreator.kt | 4 +- .../configure/EthereumUpstreamCreator.kt | 4 +- .../configure/GenericUpstreamCreator.kt | 4 +- .../startup/configure/UpstreamCreator.kt | 6 +- .../dshackle/upstream/CallTargetsHolder.kt | 6 +- .../dshackle/upstream/LogsOracle.kt | 90 ------------------ .../upstream/calls/DefaultEthereumMethods.kt | 11 --- .../ethereum/EthereumChainSpecific.kt | 4 +- .../upstream/ethereum/EthereumLocalReader.kt | 84 ---------------- .../upstream/generic/AbstractChainSpecific.kt | 2 - .../upstream/generic/ChainSpecific.kt | 4 +- .../upstream/generic/GenericMultistream.kt | 14 +-- .../polkadot/PolkadotChainSpecific.kt | 2 - src/main/resources/LogsOracle.jar | Bin 57283 -> 0 bytes .../dshackle/rpc/NativeCallSpec.groovy | 12 +-- .../dshackle/test/GenericUpstreamMock.groovy | 2 +- .../test/MultistreamHolderMock.groovy | 6 +- .../dshackle/test/TestingCommons.groovy | 11 +-- .../dshackle/upstream/FilteredApisSpec.groovy | 2 +- .../dshackle/upstream/MultistreamSpec.groovy | 12 +-- .../calls/DefaultEthereumMethodsSpec.groovy | 18 ++-- .../calls/ManagedCallMethodsSpec.groovy | 10 +- .../ethereum/EthereumCachingReaderSpec.groovy | 28 +++--- .../ethereum/EthereumLocalReaderSpec.groovy | 30 +++--- .../config/reload/ReloadConfigTest.kt | 3 - 33 files changed, 70 insertions(+), 417 deletions(-) delete mode 100644 src/main/kotlin/io/emeraldpay/dshackle/config/IndexConfig.kt delete mode 100644 src/main/kotlin/io/emeraldpay/dshackle/config/IndexConfigReader.kt delete mode 100644 src/main/kotlin/io/emeraldpay/dshackle/upstream/LogsOracle.kt delete mode 100644 src/main/resources/LogsOracle.jar diff --git a/build.gradle b/build.gradle index d23b1c3e..9d42aa73 100644 --- a/build.gradle +++ b/build.gradle @@ -122,16 +122,8 @@ dependencies { implementation(variantOf(libs.netty.tcnative.boringssl) { classifier("linux-aarch_64") }) implementation(variantOf(libs.netty.tcnative.boringssl) { classifier("osx-x86_64") }) implementation 'dshackle:foundation:1.0.0' - - implementation files('src/main/resources/LogsOracle.jar') } -// Enable 'Foreign Function & Memory API' (JEP 434) -// Drop after update on Java 21 -tasks.withType(JavaCompile) { options.compilerArgs += "--enable-preview" } -tasks.withType(Test) { jvmArgs += "--enable-preview" } -tasks.withType(JavaExec) { jvmArgs += "--enable-preview" } - compileKotlin { compilerOptions.jvmTarget.set(JvmTarget.JVM_21) } diff --git a/src/main/kotlin/io/emeraldpay/dshackle/Config.kt b/src/main/kotlin/io/emeraldpay/dshackle/Config.kt index da05fbca..b33ab61b 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/Config.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/Config.kt @@ -21,7 +21,6 @@ import io.emeraldpay.dshackle.config.CacheConfig import io.emeraldpay.dshackle.config.ChainsConfig import io.emeraldpay.dshackle.config.CompressionConfig import io.emeraldpay.dshackle.config.HealthConfig -import io.emeraldpay.dshackle.config.IndexConfig import io.emeraldpay.dshackle.config.MainConfig import io.emeraldpay.dshackle.config.MainConfigReader import io.emeraldpay.dshackle.config.MonitoringConfig @@ -131,11 +130,6 @@ open class Config( return mainConfig.cache ?: CacheConfig() } - @Bean - open fun indexConfig(@Autowired mainConfig: MainConfig): IndexConfig { - return mainConfig.index ?: IndexConfig() - } - @Bean open fun signatureConfig(@Autowired mainConfig: MainConfig): SignatureConfig { return mainConfig.signature ?: SignatureConfig() diff --git a/src/main/kotlin/io/emeraldpay/dshackle/config/IndexConfig.kt b/src/main/kotlin/io/emeraldpay/dshackle/config/IndexConfig.kt deleted file mode 100644 index 00202c6e..00000000 --- a/src/main/kotlin/io/emeraldpay/dshackle/config/IndexConfig.kt +++ /dev/null @@ -1,21 +0,0 @@ -package io.emeraldpay.dshackle.config - -import io.emeraldpay.dshackle.Chain - -class IndexConfig { - var items: HashMap = HashMap() - - class Index( - var rpc: String, - var store: String, - var ram_limit: Long?, - ) - - fun isChainEnabled(chain: Chain): Boolean { - return items.containsKey(chain) - } - - fun getByChain(chain: Chain): Index? { - return items.get(chain) - } -} diff --git a/src/main/kotlin/io/emeraldpay/dshackle/config/IndexConfigReader.kt b/src/main/kotlin/io/emeraldpay/dshackle/config/IndexConfigReader.kt deleted file mode 100644 index 1297670d..00000000 --- a/src/main/kotlin/io/emeraldpay/dshackle/config/IndexConfigReader.kt +++ /dev/null @@ -1,62 +0,0 @@ -package io.emeraldpay.dshackle.config - -import io.emeraldpay.dshackle.Chain -import io.emeraldpay.dshackle.Global -import io.emeraldpay.dshackle.foundation.YamlConfigReader -import org.apache.commons.lang3.StringUtils -import org.slf4j.LoggerFactory -import org.springframework.util.unit.DataSize -import org.yaml.snakeyaml.nodes.MappingNode - -class IndexConfigReader : YamlConfigReader() { - - companion object { - private val log = LoggerFactory.getLogger(IndexConfigReader::class.java) - } - - override fun read(input: MappingNode?): IndexConfig? { - return getList(input, "index")?.let { items -> - val config = IndexConfig() - - items.value.map { - val blockchainRaw = getValueAsString(it, "chain") - if (blockchainRaw == null || StringUtils.isEmpty(blockchainRaw) || Global.chainById(blockchainRaw) == Chain.UNSPECIFIED) { - throw InvalidConfigYamlException(filename, it.startMark, "Invalid blockchain or not specified") - } - - val blockchain = Global.chainById(blockchainRaw) - if (config.items.containsKey(blockchain)) { - throw InvalidConfigYamlException(filename, it.startMark, "Duplicated indexes") - } - - val rpc = getValueAsString(it, "rpc") - if (rpc == null || StringUtils.isEmpty(rpc)) { - throw InvalidConfigYamlException(filename, it.startMark, "Invalid rpc specified") - } - - val store = getValueAsString(it, "store") - if (store == null || StringUtils.isEmpty(store)) { - throw InvalidConfigYamlException(filename, it.startMark, "Invalid store directory or not specified") - } - - val limit = getMapping(it, "limit") - val ram_limit = limit?.let { - val raw = getValueAsString(limit, "ram") - if (raw == null || StringUtils.isEmpty(raw)) { - return null - } - - try { - DataSize.parse(raw).toBytes() - } catch (e: IllegalArgumentException) { - throw InvalidConfigYamlException(filename, it.startMark, "Invalid limit for index") - } - } - - config.items.put(blockchain, IndexConfig.Index(rpc, store, ram_limit)) - } - - config - } - } -} diff --git a/src/main/kotlin/io/emeraldpay/dshackle/config/MainConfig.kt b/src/main/kotlin/io/emeraldpay/dshackle/config/MainConfig.kt index 23b4fb7a..a1d8e4b4 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/config/MainConfig.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/config/MainConfig.kt @@ -24,7 +24,6 @@ class MainConfig { var tls: AuthConfig.ServerTlsAuth? = null var passthrough: Boolean = false var cache: CacheConfig? = null - var index: IndexConfig? = null var proxy: ProxyConfig? = null var upstreams: UpstreamsConfig? = null set(value) { diff --git a/src/main/kotlin/io/emeraldpay/dshackle/config/MainConfigReader.kt b/src/main/kotlin/io/emeraldpay/dshackle/config/MainConfigReader.kt index 7522c562..90cdef65 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/config/MainConfigReader.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/config/MainConfigReader.kt @@ -29,7 +29,6 @@ class MainConfigReader( private val optionsReader = ChainOptionsReader() private val upstreamsConfigReader = UpstreamsConfigReader(fileResolver, optionsReader) private val cacheConfigReader = CacheConfigReader() - private val indexConfigReader = IndexConfigReader() private val tokensConfigReader = TokensConfigReader() private val monitoringConfigReader = MonitoringConfigReader() private val accessLogReader = AccessLogReader() @@ -64,9 +63,6 @@ class MainConfigReader( cacheConfigReader.read(input)?.let { config.cache = it } - indexConfigReader.read(input)?.let { - config.index = it - } tokensConfigReader.read(input)?.let { config.tokens = it } diff --git a/src/main/kotlin/io/emeraldpay/dshackle/config/context/MultistreamsConfig.kt b/src/main/kotlin/io/emeraldpay/dshackle/config/context/MultistreamsConfig.kt index 6b3ba3cf..7e22c928 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/config/context/MultistreamsConfig.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/config/context/MultistreamsConfig.kt @@ -3,7 +3,6 @@ package io.emeraldpay.dshackle.config.context import io.emeraldpay.dshackle.BlockchainType.BITCOIN import io.emeraldpay.dshackle.Chain import io.emeraldpay.dshackle.cache.CachesFactory -import io.emeraldpay.dshackle.config.IndexConfig import io.emeraldpay.dshackle.upstream.CallTargetsHolder import io.emeraldpay.dshackle.upstream.Multistream import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinMultistream @@ -29,9 +28,6 @@ open class MultistreamsConfig(val beanFactory: ConfigurableListableBeanFactory) subScheduler: Scheduler, tracer: Tracer, multistreamEventsScheduler: Scheduler, - indexConfig: IndexConfig, - @Qualifier("logsOracleScheduler") - logsOracleScheduler: Scheduler, ): List { return Chain.entries .filterNot { it == Chain.UNSPECIFIED } @@ -46,8 +42,6 @@ open class MultistreamsConfig(val beanFactory: ConfigurableListableBeanFactory) subScheduler, tracer, multistreamEventsScheduler, - indexConfig.getByChain(chain), - logsOracleScheduler, ) } } @@ -60,8 +54,6 @@ open class MultistreamsConfig(val beanFactory: ConfigurableListableBeanFactory) subScheduler: Scheduler, tracer: Tracer, multistreamEventsScheduler: Scheduler, - logsOracleConfig: IndexConfig.Index?, - logsOracleScheduler: Scheduler, ): Multistream { val name = "multi-$chain" val cs = ChainSpecificRegistry.resolve(chain) @@ -76,9 +68,6 @@ open class MultistreamsConfig(val beanFactory: ConfigurableListableBeanFactory) cs.makeCachingReaderBuilder(tracer), cs::localReaderBuilder, cs.subscriptionBuilder(subScheduler), - logsOracleConfig, - logsOracleScheduler, - tracer, ).also { register(it, name) } } diff --git a/src/main/kotlin/io/emeraldpay/dshackle/config/context/SchedulersConfig.kt b/src/main/kotlin/io/emeraldpay/dshackle/config/context/SchedulersConfig.kt index ae4b068a..356aef2d 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/config/context/SchedulersConfig.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/config/context/SchedulersConfig.kt @@ -46,11 +46,6 @@ open class SchedulersConfig { return makeScheduler("sub-scheduler", 4, monitoringConfig) } - @Bean - open fun logsOracleScheduler(monitoringConfig: MonitoringConfig): Scheduler { - return makeScheduler("logs-oracle", 4, monitoringConfig) - } - @Bean open fun multistreamEventsScheduler(monitoringConfig: MonitoringConfig): Scheduler { return makeScheduler("events-scheduler", 4, monitoringConfig) diff --git a/src/main/kotlin/io/emeraldpay/dshackle/startup/configure/BitcoinUpstreamCreator.kt b/src/main/kotlin/io/emeraldpay/dshackle/startup/configure/BitcoinUpstreamCreator.kt index 8ba11072..9925aa61 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/startup/configure/BitcoinUpstreamCreator.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/startup/configure/BitcoinUpstreamCreator.kt @@ -3,7 +3,6 @@ package io.emeraldpay.dshackle.startup.configure import io.emeraldpay.dshackle.Chain import io.emeraldpay.dshackle.FileResolver import io.emeraldpay.dshackle.config.ChainsConfig -import io.emeraldpay.dshackle.config.IndexConfig import io.emeraldpay.dshackle.config.UpstreamsConfig import io.emeraldpay.dshackle.foundation.ChainOptions import io.emeraldpay.dshackle.startup.QuorumForLabels @@ -24,12 +23,11 @@ import java.util.concurrent.atomic.AtomicInteger @Component class BitcoinUpstreamCreator( chainsConfig: ChainsConfig, - indexConfig: IndexConfig, callTargets: CallTargetsHolder, private val genericConnectorFactoryCreator: ConnectorFactoryCreator, private val fileResolver: FileResolver, private val headScheduler: Scheduler, -) : UpstreamCreator(chainsConfig, indexConfig, callTargets) { +) : UpstreamCreator(chainsConfig, callTargets) { private var seq = AtomicInteger(0) override fun createUpstream( diff --git a/src/main/kotlin/io/emeraldpay/dshackle/startup/configure/EthereumUpstreamCreator.kt b/src/main/kotlin/io/emeraldpay/dshackle/startup/configure/EthereumUpstreamCreator.kt index 54df5dbc..2b9243fb 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/startup/configure/EthereumUpstreamCreator.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/startup/configure/EthereumUpstreamCreator.kt @@ -2,7 +2,6 @@ package io.emeraldpay.dshackle.startup.configure import io.emeraldpay.dshackle.Chain import io.emeraldpay.dshackle.config.ChainsConfig -import io.emeraldpay.dshackle.config.IndexConfig import io.emeraldpay.dshackle.config.UpstreamsConfig import io.emeraldpay.dshackle.config.hot.CompatibleVersionsRules import io.emeraldpay.dshackle.foundation.ChainOptions @@ -13,11 +12,10 @@ import java.util.function.Supplier @Component class EthereumUpstreamCreator( chainsConfig: ChainsConfig, - indexConfig: IndexConfig, callTargets: CallTargetsHolder, connectorFactoryCreatorResolver: ConnectorFactoryCreatorResolver, versionRules: Supplier, -) : GenericUpstreamCreator(chainsConfig, indexConfig, callTargets, connectorFactoryCreatorResolver, versionRules) { +) : GenericUpstreamCreator(chainsConfig, callTargets, connectorFactoryCreatorResolver, versionRules) { override fun createUpstream( upstreamsConfig: UpstreamsConfig.Upstream<*>, diff --git a/src/main/kotlin/io/emeraldpay/dshackle/startup/configure/GenericUpstreamCreator.kt b/src/main/kotlin/io/emeraldpay/dshackle/startup/configure/GenericUpstreamCreator.kt index b1bbfbe8..a813ea67 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/startup/configure/GenericUpstreamCreator.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/startup/configure/GenericUpstreamCreator.kt @@ -2,7 +2,6 @@ package io.emeraldpay.dshackle.startup.configure import io.emeraldpay.dshackle.Chain import io.emeraldpay.dshackle.config.ChainsConfig -import io.emeraldpay.dshackle.config.IndexConfig import io.emeraldpay.dshackle.config.UpstreamsConfig import io.emeraldpay.dshackle.config.hot.CompatibleVersionsRules import io.emeraldpay.dshackle.foundation.ChainOptions @@ -19,11 +18,10 @@ import java.util.function.Supplier @Component open class GenericUpstreamCreator( chainsConfig: ChainsConfig, - indexConfig: IndexConfig, callTargets: CallTargetsHolder, private val connectorFactoryCreatorResolver: ConnectorFactoryCreatorResolver, private val versionRules: Supplier, -) : UpstreamCreator(chainsConfig, indexConfig, callTargets) { +) : UpstreamCreator(chainsConfig, callTargets) { private val hashes = HashSet() override fun createUpstream( diff --git a/src/main/kotlin/io/emeraldpay/dshackle/startup/configure/UpstreamCreator.kt b/src/main/kotlin/io/emeraldpay/dshackle/startup/configure/UpstreamCreator.kt index 4b354f21..5a7e7f27 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/startup/configure/UpstreamCreator.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/startup/configure/UpstreamCreator.kt @@ -3,7 +3,6 @@ package io.emeraldpay.dshackle.startup.configure import io.emeraldpay.dshackle.Chain import io.emeraldpay.dshackle.Global import io.emeraldpay.dshackle.config.ChainsConfig -import io.emeraldpay.dshackle.config.IndexConfig import io.emeraldpay.dshackle.config.UpstreamsConfig import io.emeraldpay.dshackle.foundation.ChainOptions import io.emeraldpay.dshackle.foundation.ChainOptions.Options @@ -17,7 +16,6 @@ import kotlin.math.abs abstract class UpstreamCreator( private val chainsConfig: ChainsConfig, - private val indexConfig: IndexConfig, private val callTargets: CallTargetsHolder, ) { protected val log: Logger = LoggerFactory.getLogger(this::class.java) @@ -83,7 +81,7 @@ abstract class UpstreamCreator( } ManagedCallMethods( - delegate = callTargets.getDefaultMethods(chain, indexConfig.isChainEnabled(chain), options, config.connection), + delegate = callTargets.getDefaultMethods(chain, options, config.connection), enabled = config.methods?.enabled?.map { it.name }?.toSet() ?: emptySet(), disabled = config.methods?.disabled?.map { it.name }?.toSet() ?: emptySet(), groupsEnabled = config.methodGroups?.enabled ?: emptySet(), @@ -99,7 +97,7 @@ abstract class UpstreamCreator( } } } else { - callTargets.getDefaultMethods(chain, indexConfig.isChainEnabled(chain), options, config.connection) + callTargets.getDefaultMethods(chain, options, config.connection) } } } diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/CallTargetsHolder.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/CallTargetsHolder.kt index edc06ab3..22fb1368 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/CallTargetsHolder.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/CallTargetsHolder.kt @@ -29,22 +29,20 @@ class CallTargetsHolder { fun getDefaultMethods( chain: Chain, - hasLogsOracle: Boolean, options: ChainOptions.Options, connection: UpstreamsConfig.UpstreamConnection?, ): CallMethods { - return callTargets[chain] ?: return setupDefaultMethods(chain, hasLogsOracle, options, connection) + return callTargets[chain] ?: return setupDefaultMethods(chain, options, connection) } private fun setupDefaultMethods( chain: Chain, - hasLogsOracle: Boolean, options: ChainOptions.Options, connection: UpstreamsConfig.UpstreamConnection?, ): CallMethods { val created = when (chain.type) { BITCOIN -> DefaultBitcoinMethods(options.providesBalance == true) - ETHEREUM -> DefaultEthereumMethods(chain, hasLogsOracle) + ETHEREUM -> DefaultEthereumMethods(chain) STARKNET -> DefaultStarknetMethods(chain) POLKADOT -> DefaultPolkadotMethods(chain) SOLANA -> DefaultSolanaMethods() diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/LogsOracle.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/LogsOracle.kt deleted file mode 100644 index 13b4e564..00000000 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/LogsOracle.kt +++ /dev/null @@ -1,90 +0,0 @@ -package io.emeraldpay.dshackle.upstream - -import io.emeraldpay.dshackle.config.IndexConfig -import org.slf4j.LoggerFactory -import org.springframework.cloud.sleuth.Tracer -import reactor.core.Disposable -import reactor.core.publisher.Mono -import reactor.core.scheduler.Scheduler - -class LogsOracle( - private val config: IndexConfig.Index, - private val upstream: Multistream, - private val scheduler: Scheduler, - private val tracer: Tracer, -) { - - private val log = LoggerFactory.getLogger(LogsOracle::class.java) - - private var subscription: Disposable? = null - private var conn: org.drpc.logsoracle.LogsOracle? = null - - fun start() { - log.info("liboracle starting: store=${config.store}, ram=${config.ram_limit}") - - conn = org.drpc.logsoracle.LogsOracle(config.store, config.ram_limit ?: 0L) - subscription = upstream.getHead().getFlux() - .publishOn(scheduler) - .doOnError { t -> log.error("Failed to subscribe head for oracle", t) } - .doFinally { log.info("unsubscribe head") } - .subscribe { setHeight(it.height) } - - setUpstream(config.rpc) - } - - fun stop() { - log.info("liboracle closed") - - subscription?.dispose() - subscription = null - - conn?.close() - } - - fun estimate( - limit: Long?, - fromBlock: Long, - toBlock: Long, - address: List, - topics: List>, - ): Mono { - val requestSpan = tracer.currentSpan() - - return Mono.fromCallable { - val span = tracer.nextSpan(requestSpan).name("emerald.blockchain/logsoracle").start() - log.info("query: from=$fromBlock, to=$toBlock, limit=$limit") - - try { - val estimate = conn?.Query(limit, fromBlock, toBlock, address, topics) - "{\"total\":$estimate,\"overflow\":false}" - } catch (e: org.drpc.logsoracle.LogsOracle.LogsOracleException) { - if (e.isQueryOverflow()) { - "{\"total\":-1,\"overflow\":true}" - } else { - throw e - } - } finally { - span.end() - } - } - .publishOn(scheduler) - } - - fun setHeight(height: Long) { - try { - log.info("update state: height=$height") - conn?.UpdateHeight(height) - } catch (e: Exception) { - log.error("couldn't set height", e) - } - } - - fun setUpstream(upstream: String) { - try { - log.info("update state: upstream=$upstream") - conn?.SetUpstream(upstream) - } catch (e: Exception) { - log.error("couldn't set upstream", e) - } - } -} diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/calls/DefaultEthereumMethods.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/calls/DefaultEthereumMethods.kt index 7a74581f..d9739b36 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/calls/DefaultEthereumMethods.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/calls/DefaultEthereumMethods.kt @@ -31,7 +31,6 @@ import io.emeraldpay.dshackle.upstream.ethereum.rpc.RpcException */ class DefaultEthereumMethods( private val chain: Chain, - private val hasLogsOracle: Boolean = false, ) : CallMethods { private val version = "\"EmeraldDshackle/${Global.version}\"" @@ -613,7 +612,6 @@ class DefaultEthereumMethods( specialMethods + headVerifiedMethods - chainUnsupportedMethods(chain) + - getDrpcVendorMethods(chain) + getChainSpecificMethods(chain) } @@ -632,15 +630,6 @@ class DefaultEthereumMethods( } } - private fun getDrpcVendorMethods(chain: Chain): List { - val supported = mutableListOf() - - // Currently tested on eth mainnet only, should potentially work for all compatible ones. - if (chain == Chain.ETHEREUM__MAINNET && hasLogsOracle) { supported.add("drpc_getLogsEstimate") } - - return supported - } - private fun getChainSpecificMethods(chain: Chain): List { return when (chain) { Chain.OPTIMISM__MAINNET, Chain.OPTIMISM__SEPOLIA -> diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/ethereum/EthereumChainSpecific.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/ethereum/EthereumChainSpecific.kt index 7df4311b..0191a83d 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/ethereum/EthereumChainSpecific.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/ethereum/EthereumChainSpecific.kt @@ -14,7 +14,6 @@ import io.emeraldpay.dshackle.upstream.EgressSubscription import io.emeraldpay.dshackle.upstream.GenericSingleCallValidator import io.emeraldpay.dshackle.upstream.Head import io.emeraldpay.dshackle.upstream.IngressSubscription -import io.emeraldpay.dshackle.upstream.LogsOracle import io.emeraldpay.dshackle.upstream.Multistream import io.emeraldpay.dshackle.upstream.SingleValidator import io.emeraldpay.dshackle.upstream.Upstream @@ -65,9 +64,8 @@ object EthereumChainSpecific : AbstractPollChainSpecific() { cachingReader: CachingReader, methods: CallMethods, head: Head, - logsOracle: LogsOracle?, ): Mono { - return Mono.just(EthereumLocalReader(cachingReader as EthereumCachingReader, methods, head, logsOracle)) + return Mono.just(EthereumLocalReader(cachingReader as EthereumCachingReader, methods, head)) } override fun subscriptionBuilder(headScheduler: Scheduler): (Multistream) -> EgressSubscription { diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/ethereum/EthereumLocalReader.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/ethereum/EthereumLocalReader.kt index cabab516..6a70891e 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/ethereum/EthereumLocalReader.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/ethereum/EthereumLocalReader.kt @@ -22,7 +22,6 @@ import io.emeraldpay.dshackle.reader.ChainReader import io.emeraldpay.dshackle.upstream.ChainRequest import io.emeraldpay.dshackle.upstream.ChainResponse import io.emeraldpay.dshackle.upstream.Head -import io.emeraldpay.dshackle.upstream.LogsOracle import io.emeraldpay.dshackle.upstream.Selector import io.emeraldpay.dshackle.upstream.calls.CallMethods import io.emeraldpay.dshackle.upstream.ethereum.hex.HexQuantity @@ -46,7 +45,6 @@ class EthereumLocalReader( private val reader: EthereumCachingReader, private val methods: CallMethods, private val head: Head, - private val logsOracle: LogsOracle?, ) : ChainReader { override fun read(key: ChainRequest): Mono { @@ -132,10 +130,6 @@ class EthereumLocalReader( .map { ChainResponse(it.data, null, it.resolvedUpstreamData) } } - method == "drpc_getLogsEstimate" -> { - getLogsEstimate(params.list) - } - else -> null } } @@ -193,82 +187,4 @@ class EthereumLocalReader( return reader.blocksByHeightAsCont(upstreamFilter) .read(number).map { ChainResponse(it.data.json, null, it.resolvedUpstreamData) } } - - fun getLogsEstimate(params: List): Mono? { - if (logsOracle == null) { - throw NotImplementedError() - } - if (params.size != 1 || params[0] == null) { - throw RpcException(RpcResponseError.CODE_INVALID_METHOD_PARAMS, "Must provide 1 parameters") - } - - val req = params[0] as LinkedHashMap - - val limit = try { req.get("limit") as Int? } catch (_: IllegalArgumentException) { - throw RpcException(RpcResponseError.CODE_INVALID_METHOD_PARAMS, "Invalid 'limit' parameter") - } - - val fromBlock = try { parseBlockRef(req.get("fromBlock") as String?) } catch (_: IllegalArgumentException) { - throw RpcException(RpcResponseError.CODE_INVALID_METHOD_PARAMS, "Invalid 'fromBlock' parameter") - } - val toBlock = try { parseBlockRef(req.get("toBlock") as String?) } catch (_: IllegalArgumentException) { - throw RpcException(RpcResponseError.CODE_INVALID_METHOD_PARAMS, "Invalid 'toBlock' parameter") - } - val address: List = try { - val it = req.get("address") ?: listOf() - - if (it is String) { - listOf(it) - } else { - it as List - } - } catch (_: Exception) { - throw RpcException(RpcResponseError.CODE_INVALID_METHOD_PARAMS, "Invalid 'address' parameter") - } - val topics: List> = try { - val tpcs = req.get("topics")?.let { it as List } ?: listOf() - if (tpcs.size > 4) { - throw IllegalArgumentException() - } - - tpcs.map { - if (it == null) { - emptyList() - } else if (it is String) { - listOf(it) - } else { - it as List - } - } - } catch (_: Exception) { - throw RpcException(RpcResponseError.CODE_INVALID_METHOD_PARAMS, "Invalid 'topics' parameter") - } - - return logsOracle.estimate(limit?.toLong(), fromBlock, toBlock, address, topics) - .map { ChainResponse(it.toByteArray(), null, emptyList()) } - } - - private fun parseBlockRef(blockRef: String?): Long { - when { - blockRef == "earliest" -> { - return 0 - } - blockRef == null || blockRef == "finalized" || blockRef == "safe" || blockRef == "pending" || blockRef == "latest" -> { - return head.getCurrentHeight() ?: throw Exception("couldn't get current head") - } - blockRef.startsWith("0x") -> { - val quantity = HexQuantity.from(blockRef) ?: throw IllegalArgumentException() - return quantity.value.let { - if (it < BigInteger.valueOf(Long.MAX_VALUE) && it >= BigInteger.ZERO) { - it.toLong() - } else { - throw IllegalArgumentException() - } - } - } - else -> { - throw IllegalArgumentException() - } - } - } } diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/generic/AbstractChainSpecific.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/generic/AbstractChainSpecific.kt index ee5e922e..559c42c6 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/generic/AbstractChainSpecific.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/generic/AbstractChainSpecific.kt @@ -14,7 +14,6 @@ import io.emeraldpay.dshackle.upstream.EgressSubscription import io.emeraldpay.dshackle.upstream.EmptyEgressSubscription import io.emeraldpay.dshackle.upstream.Head import io.emeraldpay.dshackle.upstream.IngressSubscription -import io.emeraldpay.dshackle.upstream.LogsOracle import io.emeraldpay.dshackle.upstream.Multistream import io.emeraldpay.dshackle.upstream.NoIngressSubscription import io.emeraldpay.dshackle.upstream.NoopCachingReader @@ -41,7 +40,6 @@ abstract class AbstractChainSpecific : ChainSpecific { cachingReader: CachingReader, methods: CallMethods, head: Head, - logsOracle: LogsOracle?, ): Mono { return Mono.just(LocalReader(methods)) } diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/generic/ChainSpecific.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/generic/ChainSpecific.kt index 0c919a43..b060c113 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/generic/ChainSpecific.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/generic/ChainSpecific.kt @@ -23,7 +23,6 @@ import io.emeraldpay.dshackle.upstream.ChainRequest import io.emeraldpay.dshackle.upstream.EgressSubscription import io.emeraldpay.dshackle.upstream.Head import io.emeraldpay.dshackle.upstream.IngressSubscription -import io.emeraldpay.dshackle.upstream.LogsOracle import io.emeraldpay.dshackle.upstream.Multistream import io.emeraldpay.dshackle.upstream.SingleValidator import io.emeraldpay.dshackle.upstream.Upstream @@ -51,7 +50,7 @@ import reactor.core.scheduler.Scheduler import java.util.function.Supplier typealias SubscriptionBuilder = (Multistream) -> EgressSubscription -typealias LocalReaderBuilder = (CachingReader, CallMethods, Head, LogsOracle?) -> Mono +typealias LocalReaderBuilder = (CachingReader, CallMethods, Head) -> Mono typealias CachingReaderBuilder = (Multistream, Caches, Factory) -> CachingReader typealias FinalizationDetectorBuilder = () -> FinalizationDetector @@ -70,7 +69,6 @@ interface ChainSpecific { cachingReader: CachingReader, methods: CallMethods, head: Head, - logsOracle: LogsOracle?, ): Mono fun subscriptionBuilder(headScheduler: Scheduler): (Multistream) -> EgressSubscription diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/generic/GenericMultistream.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/generic/GenericMultistream.kt index 564ae4c6..5ee9ede7 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/generic/GenericMultistream.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/generic/GenericMultistream.kt @@ -19,7 +19,6 @@ package io.emeraldpay.dshackle.upstream.generic import io.emeraldpay.api.proto.BlockchainOuterClass import io.emeraldpay.dshackle.Chain import io.emeraldpay.dshackle.cache.Caches -import io.emeraldpay.dshackle.config.IndexConfig import io.emeraldpay.dshackle.config.UpstreamsConfig import io.emeraldpay.dshackle.reader.ChainReader import io.emeraldpay.dshackle.upstream.CachingReader @@ -30,7 +29,6 @@ import io.emeraldpay.dshackle.upstream.EmptyHead import io.emeraldpay.dshackle.upstream.Head import io.emeraldpay.dshackle.upstream.HeadLagObserver import io.emeraldpay.dshackle.upstream.Lifecycle -import io.emeraldpay.dshackle.upstream.LogsOracle import io.emeraldpay.dshackle.upstream.MergedHead import io.emeraldpay.dshackle.upstream.Multistream import io.emeraldpay.dshackle.upstream.Selector @@ -39,7 +37,6 @@ import io.emeraldpay.dshackle.upstream.Upstream import io.emeraldpay.dshackle.upstream.calls.CallSelector import io.emeraldpay.dshackle.upstream.forkchoice.PriorityForkChoice import io.emeraldpay.dshackle.upstream.grpc.GrpcUpstream -import org.springframework.cloud.sleuth.Tracer import org.springframework.util.ConcurrentReferenceHashMap import org.springframework.util.ConcurrentReferenceHashMap.ReferenceType.WEAK import reactor.core.publisher.Flux @@ -56,9 +53,6 @@ open class GenericMultistream( cachingReaderBuilder: CachingReaderBuilder, private val localReaderBuilder: LocalReaderBuilder, private val subscriptionBuilder: SubscriptionBuilder, - logsOracleConfig: IndexConfig.Index? = null, - private val logsOracleScheduler: Scheduler, - private val tracer: Tracer, ) : Multistream(chain, caches, callSelector, multistreamEventsScheduler) { private val cachingReader = cachingReaderBuilder(this, caches, getMethodsFactory()) @@ -77,10 +71,6 @@ open class GenericMultistream( headScheduler, ) - private val logsOracle: LogsOracle? = logsOracleConfig?.let { - LogsOracle(logsOracleConfig, this, logsOracleScheduler, tracer) - } - private var subscription: EgressSubscription = subscriptionBuilder(this) private val filteredHeads: MutableMap = @@ -91,14 +81,12 @@ open class GenericMultistream( head.start() onHeadUpdated(head) cachingReader.start() - logsOracle?.start() } override fun stop() { super.stop() cachingReader.stop() filteredHeads.clear() - logsOracle?.stop() } override fun addHead(upstream: Upstream) { @@ -167,7 +155,7 @@ open class GenericMultistream( } override fun getLocalReader(): Mono { - return localReaderBuilder(cachingReader, getMethods(), getHead(), logsOracle) + return localReaderBuilder(cachingReader, getMethods(), getHead()) } override fun getEgressSubscription(): EgressSubscription { diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/polkadot/PolkadotChainSpecific.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/polkadot/PolkadotChainSpecific.kt index 6325ae18..ae8b3b79 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/polkadot/PolkadotChainSpecific.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/polkadot/PolkadotChainSpecific.kt @@ -16,7 +16,6 @@ import io.emeraldpay.dshackle.upstream.EgressSubscription import io.emeraldpay.dshackle.upstream.GenericSingleCallValidator import io.emeraldpay.dshackle.upstream.Head import io.emeraldpay.dshackle.upstream.IngressSubscription -import io.emeraldpay.dshackle.upstream.LogsOracle import io.emeraldpay.dshackle.upstream.Multistream import io.emeraldpay.dshackle.upstream.SingleValidator import io.emeraldpay.dshackle.upstream.Upstream @@ -80,7 +79,6 @@ object PolkadotChainSpecific : AbstractPollChainSpecific() { cachingReader: CachingReader, methods: CallMethods, head: Head, - logsOracle: LogsOracle?, ): Mono { return Mono.just(LocalReader(methods)) } diff --git a/src/main/resources/LogsOracle.jar b/src/main/resources/LogsOracle.jar deleted file mode 100644 index d4159295d3b2bcd8c54987c8baab5a2b7536d175..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 57283 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%0DtotpE%kbON@{R`#*OW zs@bM~Wmlhfqw?blj%gb`i?&=4p4SN0i-W#Vv%6sJNL{%Nj~Z2SI5_!h`Ga9)o+}*! zs{}4C+W4n}uTx!LS&g{Nk<94l>BuC2oZg?qY<+lJmGV?=7w8@6^x}FPZ227P%gZta z=+ds^YMey|AAJR})SFJ%xYF{s!*$mtYG==nwrEiPL;YSm#SA?wG`)10R(u zz!xgWnY{|;gWO!}cEYUjjn!%EYegXKu98v45WGHcvwA}7RF`CUuSiBp!wYmxjG#xj zqkc}Md$6VTyBea3ez0=3tIq&WIzJ64J+3^lSL`q9prSUf@;8~@HlLEI@HfhT!OF;q zkaux*zHn*$rWfOuwLs_dq>=X$K!XD8@&xs?)** zqTr(kVR#tDl>z+rRlRr^^#-4Wm(~hB@cl42gn^Bn zyT8l(5(l~q55U-vlrOLF#~sDc#xK(VC`~+=-U^JY$!xjsxT14}K;w*(gcXg-qorg= z_My6IQ<>a=9sH5%ch5ypOmreVQLhg@38W#(eB|d3x;hM2#MhpbED=a+56&(1&s*TJwW z{A`}Xb=LUpi$1v>z{`#yK1xeLg73VCX@n@#m&OF&xi%ooNFBT?vUBK5I6IOg6f?p4 z_08>;tQ{f>bRqy|9L}J#IsiGx=12yF{Fq z7Y-{y7K?x1&+I7bep7;+&^;HYsGN^jODjckf&vo&=9S%L5Wn{Tm_fKqZub)8{0h{j z8h%!a#PFCc!e z0WiJrj+|~-aW`ohavg+nqWE6i?R_uTuMU94WPk!Q0Ubu+KTDBJ6zyu^GeM5lmxHLc zL%A=e2fY&B7xQH9f%7G&)M8zyyhv%jy;MB=F!jyOi?==Xz!SS33OH(BAh;O*=5Cde zNvPkAHSPYhNE#`hZ$!_`i%XR=!-{i)yJdmAg?8hd*8_6Ff~C`3qLC(g5}mBa-yM%w z=haA!r2H^-hP2_<)UUlTe)!`T00qC@RXfgqMhr|^Rlq#Jvu#mKw^XI;s%0$fd%CmU zG8M0}YRi+1jI?EgnkM9BIPvIfXq$9L!QB!2k1=vciNl-|U=z9#KADLCSO?=)`%gMW z-*T|cwB#EEdFm$HsRMiU?qoA_ugltECZ7zOcL#*<2U+kDaSF($2M_tl13)7259wCB z;Z{rTYPq}8TaxTABW7ONf@Ze1@bm92m5DXiFp7oK#L-ZWpet4onvezkX`z^r(qbF+ zF%X=P=0)-abYz%e_7Fv@|Hac48l8DE8qe_Ud|IBUlxOjlm%C(U2n+tu~8`v=) z1iRArMWJW&l6=R4j4$6H1o!I|iuS%vyY20hN!TuDtkIes@10GN`FQ_)Q@u^&4$DNw|0b8~_duAr6kkEj|OR9n!x75f1*p(*I1TgLUP2 zR5TR%(8K=}CC4GhAtWUHhv@S0vn>T|xhL42{4auB*xbKF)#Wr)6u~;Wyy}X-EB}*F zg$qHeW9#%M!ogww3!xgDbM>&}v-WVa;&XPj^K|uiZslylC+`aN^m-2U^5nI0e(ve{ zpTL5nY&TUr92_$&RO~N6O@hA%s$toh|6sHHI|=r)vT^fraE1PTEtWc}lg}t{aJcw! za9I9Q%kNhGJGK9f{(E9&jU}1Q4IG^1TUhE}hPxP>IHh1^7@$ff)Zf)&h()) @@ -628,7 +628,7 @@ class NativeCallSpec extends Specification { setup: def quorum = new AlwaysQuorum() def methods = new ManagedCallMethods( - new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false), + new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET), [] as Set, [] as Set, ["filter"] as Set, [] as Set ) def multistream = new MultistreamHolderMock.EthereumMultistreamMock(Chain.ETHEREUM__MAINNET, new ArrayList()) diff --git a/src/test/groovy/io/emeraldpay/dshackle/test/GenericUpstreamMock.groovy b/src/test/groovy/io/emeraldpay/dshackle/test/GenericUpstreamMock.groovy index 63be21b2..b22bff24 100644 --- a/src/test/groovy/io/emeraldpay/dshackle/test/GenericUpstreamMock.groovy +++ b/src/test/groovy/io/emeraldpay/dshackle/test/GenericUpstreamMock.groovy @@ -38,7 +38,7 @@ class GenericUpstreamMock extends GenericUpstream { static CallMethods allMethods() { new AggregatedCallMethods([ - new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false), + new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET), new DefaultBitcoinMethods(true), new DirectCallMethods(["eth_test"]) ]) diff --git a/src/test/groovy/io/emeraldpay/dshackle/test/MultistreamHolderMock.groovy b/src/test/groovy/io/emeraldpay/dshackle/test/MultistreamHolderMock.groovy index 933b4ba4..ee98b05e 100644 --- a/src/test/groovy/io/emeraldpay/dshackle/test/MultistreamHolderMock.groovy +++ b/src/test/groovy/io/emeraldpay/dshackle/test/MultistreamHolderMock.groovy @@ -52,8 +52,6 @@ class MultistreamHolderMock implements MultistreamHolder { EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(TestingCommons.tracerMock()), EthereumChainSpecific.INSTANCE.&localReaderBuilder, io.emeraldpay.dshackle.upstream.starknet.StarknetChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()), - null, Schedulers.immediate(), - TestingCommons.tracerMock() ) upstreams[chain].addUpstream(up) } else { @@ -106,8 +104,8 @@ class MultistreamHolderMock implements MultistreamHolder { super(chain, Schedulers.immediate(), null, upstreams, caches, Schedulers.boundedElastic(), EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(new BraveTracer(null, null, null)), EthereumChainSpecific.INSTANCE.&localReaderBuilder, - EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()), null, Schedulers.immediate(), - new BraveTracer(null, null, null)) + EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()), + ) } EthereumMultistreamMock(@NotNull Chain chain, @NotNull List upstreams) { diff --git a/src/test/groovy/io/emeraldpay/dshackle/test/TestingCommons.groovy b/src/test/groovy/io/emeraldpay/dshackle/test/TestingCommons.groovy index 27c03b8f..b0af252b 100644 --- a/src/test/groovy/io/emeraldpay/dshackle/test/TestingCommons.groovy +++ b/src/test/groovy/io/emeraldpay/dshackle/test/TestingCommons.groovy @@ -102,9 +102,6 @@ class TestingCommons { EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(tracerMock()), EthereumChainSpecific.INSTANCE.&localReaderBuilder, EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()), - null, - Schedulers.immediate(), - tracerMock() ).tap { it.processUpstreamsEvents( new UpstreamChangeEvent(Chain.ETHEREUM__MAINNET, up, UpstreamChangeEvent.ChangeType.ADDED) @@ -132,9 +129,7 @@ class TestingCommons { EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(tracerMock()), EthereumChainSpecific.INSTANCE.&localReaderBuilder, EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()), - null, - Schedulers.immediate(), - tracerMock()) + ) } static Multistream multistreamClassicWithoutUpstreams(Chain chain) { @@ -142,9 +137,7 @@ class TestingCommons { EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(tracerMock()), EthereumChainSpecific.INSTANCE.&localReaderBuilder, EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()), - null, - Schedulers.immediate(), - tracerMock()) + ) } static FileResolver fileResolver() { diff --git a/src/test/groovy/io/emeraldpay/dshackle/upstream/FilteredApisSpec.groovy b/src/test/groovy/io/emeraldpay/dshackle/upstream/FilteredApisSpec.groovy index d0e5da75..417a3227 100644 --- a/src/test/groovy/io/emeraldpay/dshackle/upstream/FilteredApisSpec.groovy +++ b/src/test/groovy/io/emeraldpay/dshackle/upstream/FilteredApisSpec.groovy @@ -37,7 +37,7 @@ import static java.util.List.of class FilteredApisSpec extends Specification { - def ethereumTargets = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false) + def ethereumTargets = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET) def "Verifies labels"() { setup: diff --git a/src/test/groovy/io/emeraldpay/dshackle/upstream/MultistreamSpec.groovy b/src/test/groovy/io/emeraldpay/dshackle/upstream/MultistreamSpec.groovy index 63bb374f..e17746d2 100644 --- a/src/test/groovy/io/emeraldpay/dshackle/upstream/MultistreamSpec.groovy +++ b/src/test/groovy/io/emeraldpay/dshackle/upstream/MultistreamSpec.groovy @@ -57,7 +57,7 @@ class MultistreamSpec extends Specification { Schedulers.boundedElastic(), EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(TestingCommons.tracerMock()), EthereumChainSpecific.INSTANCE.&localReaderBuilder, - EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()), null, Schedulers.immediate(), TestingCommons.tracerMock()) + EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic())) when: aggr.onUpstreamsUpdated() def act = aggr.getMethods() @@ -192,7 +192,7 @@ class MultistreamSpec extends Specification { Schedulers.boundedElastic(), EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(TestingCommons.tracerMock()), EthereumChainSpecific.INSTANCE.&localReaderBuilder, - EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()), null, Schedulers.immediate(), TestingCommons.tracerMock()) + EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic())) expect: multistream.getHead(new Selector.LabelMatcher("provider", ["internal"])).is(up1.ethereumHeadMock) @@ -265,7 +265,7 @@ class MultistreamSpec extends Specification { Schedulers.boundedElastic(), EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(TestingCommons.tracerMock()), EthereumChainSpecific.INSTANCE.&localReaderBuilder, - EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()), null, Schedulers.immediate(), TestingCommons.tracerMock()) + EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic())) when: ms.processUpstreamsEvents( new UpstreamChangeEvent(Chain.ETHEREUM__MAINNET, up1, UpstreamChangeEvent.ChangeType.ADDED) @@ -296,7 +296,7 @@ class MultistreamSpec extends Specification { Schedulers.boundedElastic(), EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(TestingCommons.tracerMock()), EthereumChainSpecific.INSTANCE.&localReaderBuilder, - EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()), null, Schedulers.immediate(), TestingCommons.tracerMock()) + EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic())) def head1 = createBlock(250, "0x0d050c785de17179f935b9b93aca09c442964cc59972c71ae68e74731448401b") def head2 = createBlock(270, "0x0d050c785de17179f935b9b93aca09c442964cc59972c71ae68e74731448402b") def head3 = createBlock(100, "0x0d050c785de17179f935b9b93aca09c442964cc59972c71ae68e74731448412b") @@ -331,7 +331,7 @@ class MultistreamSpec extends Specification { Schedulers.boundedElastic(), EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(TestingCommons.tracerMock()), EthereumChainSpecific.INSTANCE.&localReaderBuilder, - EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()), null, Schedulers.immediate(), TestingCommons.tracerMock()) + EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic())) multistream.processUpstreamsEvents( new UpstreamChangeEvent(Chain.ETHEREUM__MAINNET, up1, UpstreamChangeEvent.ChangeType.ADDED) ) @@ -369,7 +369,7 @@ class MultistreamSpec extends Specification { Schedulers.boundedElastic(), EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(TestingCommons.tracerMock()), EthereumChainSpecific.INSTANCE.&localReaderBuilder, - StarknetChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()), null, Schedulers.immediate(), TestingCommons.tracerMock()) + StarknetChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic())) } @NotNull diff --git a/src/test/groovy/io/emeraldpay/dshackle/upstream/calls/DefaultEthereumMethodsSpec.groovy b/src/test/groovy/io/emeraldpay/dshackle/upstream/calls/DefaultEthereumMethodsSpec.groovy index 91364a6d..b672cac2 100644 --- a/src/test/groovy/io/emeraldpay/dshackle/upstream/calls/DefaultEthereumMethodsSpec.groovy +++ b/src/test/groovy/io/emeraldpay/dshackle/upstream/calls/DefaultEthereumMethodsSpec.groovy @@ -7,7 +7,7 @@ class DefaultEthereumMethodsSpec extends Specification { def "eth_chainId is available"() { setup: - def methods = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false) + def methods = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET) when: def act = methods.isAvailable("eth_chainId") then: @@ -16,7 +16,7 @@ class DefaultEthereumMethodsSpec extends Specification { def "eth_chainId is hardcoded"() { setup: - def methods = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false) + def methods = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET) when: def act = methods.isHardcoded("eth_chainId") then: @@ -25,7 +25,7 @@ class DefaultEthereumMethodsSpec extends Specification { def "eth_chainId is not callable"() { setup: - def methods = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false) + def methods = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET) when: def act = methods.isCallable("eth_chainId") then: @@ -34,7 +34,7 @@ class DefaultEthereumMethodsSpec extends Specification { def "Provides hardcoded correct chainId"() { expect: - new String(new DefaultEthereumMethods(chain, false).executeHardcoded("eth_chainId")) == id + new String(new DefaultEthereumMethods(chain).executeHardcoded("eth_chainId")) == id where: chain | id Chain.ETHEREUM__MAINNET | '"0x1"' @@ -43,7 +43,7 @@ class DefaultEthereumMethodsSpec extends Specification { def "Optimism chain unsupported methods"() { setup: - def methods = new DefaultEthereumMethods(Chain.OPTIMISM__MAINNET, false) + def methods = new DefaultEthereumMethods(Chain.OPTIMISM__MAINNET) when: def acc = methods.isAvailable("eth_getAccounts") def trans = methods.isAvailable("eth_sendTransaction") @@ -54,7 +54,7 @@ class DefaultEthereumMethodsSpec extends Specification { def "Has supported specific methods"() { expect: - new DefaultEthereumMethods(chain, false).getSupportedMethods().containsAll(methods) + new DefaultEthereumMethods(chain).getSupportedMethods().containsAll(methods) where: chain | methods Chain.POLYGON__MAINNET | ["bor_getAuthor", @@ -68,7 +68,7 @@ class DefaultEthereumMethodsSpec extends Specification { def "Has no filter methods by default"() { setup: - def methods = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false) + def methods = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET) when: def act = methods.getSupportedMethods().findAll { it.containsIgnoreCase("filter") } then: @@ -77,7 +77,7 @@ class DefaultEthereumMethodsSpec extends Specification { def "Has no trace methods by default"() { setup: - def methods = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false) + def methods = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET) when: def act = methods.getSupportedMethods().findAll { it.containsIgnoreCase("trace") } then: @@ -86,7 +86,7 @@ class DefaultEthereumMethodsSpec extends Specification { def "Default eth methods are available"() { setup: - def methods = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false) + def methods = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET) expect: methods.isAvailable(method) where: diff --git a/src/test/groovy/io/emeraldpay/dshackle/upstream/calls/ManagedCallMethodsSpec.groovy b/src/test/groovy/io/emeraldpay/dshackle/upstream/calls/ManagedCallMethodsSpec.groovy index a5350d19..fa4c1de4 100644 --- a/src/test/groovy/io/emeraldpay/dshackle/upstream/calls/ManagedCallMethodsSpec.groovy +++ b/src/test/groovy/io/emeraldpay/dshackle/upstream/calls/ManagedCallMethodsSpec.groovy @@ -94,7 +94,7 @@ class ManagedCallMethodsSpec extends Specification { def "Use custom quorum if provided"() { setup: def managed = new ManagedCallMethods( - new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false), + new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET), ["eth_test", "eth_foo", "eth_bar"] as Set, [] as Set, [] as Set, @@ -120,7 +120,7 @@ class ManagedCallMethodsSpec extends Specification { def "Doesn't reuse same instance"() { def managed = new ManagedCallMethods( - new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false), + new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET), ["eth_test"] as Set, [] as Set, [] as Set, @@ -145,7 +145,7 @@ class ManagedCallMethodsSpec extends Specification { def "Test enable method group"() { setup: def managed = new ManagedCallMethods( - new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false), + new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET), [] as Set, [] as Set, ["filter"] as Set, @@ -169,7 +169,7 @@ class ManagedCallMethodsSpec extends Specification { def "Test enable method group minus one"() { setup: def managed = new ManagedCallMethods( - new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false), + new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET), [] as Set, ["eth_newPendingTransactionFilter"] as Set, ["filter"] as Set, @@ -193,7 +193,7 @@ class ManagedCallMethodsSpec extends Specification { def "Test disabled group not disable enabled method"() { setup: def managed = new ManagedCallMethods( - new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false), + new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET), ["eth_newPendingTransactionFilter"] as Set, [] as Set, [] as Set, diff --git a/src/test/groovy/io/emeraldpay/dshackle/upstream/ethereum/EthereumCachingReaderSpec.groovy b/src/test/groovy/io/emeraldpay/dshackle/upstream/ethereum/EthereumCachingReaderSpec.groovy index 157e1cee..8db74557 100644 --- a/src/test/groovy/io/emeraldpay/dshackle/upstream/ethereum/EthereumCachingReaderSpec.groovy +++ b/src/test/groovy/io/emeraldpay/dshackle/upstream/ethereum/EthereumCachingReaderSpec.groovy @@ -45,7 +45,7 @@ class EthereumDirectReaderSpec extends Specification { transactions = [] } def calls = Mock(Factory) { - 1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false) + 1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET) } EthereumDirectReader reader = new EthereumDirectReader( Stub(Multistream), Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock() @@ -80,7 +80,7 @@ class EthereumDirectReaderSpec extends Specification { transactions = [] } def calls = Mock(Factory) { - 1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false) + 1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET) } EthereumDirectReader reader = new EthereumDirectReader( Stub(Multistream), Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock() @@ -107,7 +107,7 @@ class EthereumDirectReaderSpec extends Specification { def "Produce empty result on non-existing block"() { setup: def calls = Mock(Factory) { - 1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false) + 1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET) } EthereumDirectReader reader = new EthereumDirectReader( Stub(Multistream), Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock() @@ -140,7 +140,7 @@ class EthereumDirectReaderSpec extends Specification { transactions = [] } def calls = Mock(Factory) { - 1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false) + 1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET) } EthereumDirectReader reader = new EthereumDirectReader( Stub(Multistream), Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock() @@ -172,7 +172,7 @@ class EthereumDirectReaderSpec extends Specification { blockHash = BlockHash.from(hash1) } def calls = Mock(Factory) { - 1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false) + 1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET) } EthereumDirectReader reader = new EthereumDirectReader( Stub(Multistream), Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock() @@ -205,7 +205,7 @@ class EthereumDirectReaderSpec extends Specification { blockHash = BlockHash.from(hash1) } def calls = Mock(Factory) { - 1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false) + 1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET) } EthereumDirectReader reader = new EthereumDirectReader( Stub(Multistream), Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock() @@ -238,7 +238,7 @@ class EthereumDirectReaderSpec extends Specification { blockHash = BlockHash.from(hash1) } def calls = Mock(Factory) { - 1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false) + 1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET) } EthereumDirectReader reader = new EthereumDirectReader( Stub(Multistream), Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock() @@ -268,7 +268,7 @@ class EthereumDirectReaderSpec extends Specification { blockHash = BlockHash.from(hash1) } def calls = Mock(Factory) { - 1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false) + 1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET) } def caches = Mock(Caches) { // note that the Caches needs a Height value, otherwise it's not cached @@ -297,7 +297,7 @@ class EthereumDirectReaderSpec extends Specification { def "Produce empty on non-existing tx"() { setup: def calls = Mock(Factory) { - 1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false) + 1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET) } EthereumDirectReader reader = new EthereumDirectReader( Stub(Multistream), Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock() @@ -327,7 +327,7 @@ class EthereumDirectReaderSpec extends Specification { } } def calls = Mock(Factory) { - 1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false) + 1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET) } EthereumDirectReader reader = new EthereumDirectReader( up, Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock() @@ -358,7 +358,7 @@ class EthereumDirectReaderSpec extends Specification { } } def calls = Mock(Factory) { - 1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false) + 1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET) } EthereumDirectReader reader = new EthereumDirectReader( up, Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock() @@ -392,7 +392,7 @@ class EthereumDirectReaderSpec extends Specification { transactions = [] } def calls = Mock(Factory) { - 3 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false) + 3 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET) } def result = Mono.just( new RequestReader.Result( @@ -432,7 +432,7 @@ class EthereumDirectReaderSpec extends Specification { transactions = [] } def calls = Mock(Factory) { - 3 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false) + 3 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET) } def result = Mono.just( new RequestReader.Result( @@ -469,7 +469,7 @@ class EthereumDirectReaderSpec extends Specification { } } def calls = Mock(Factory) { - 4 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false) + 4 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET) } EthereumDirectReader reader = new EthereumDirectReader( up, Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock() diff --git a/src/test/groovy/io/emeraldpay/dshackle/upstream/ethereum/EthereumLocalReaderSpec.groovy b/src/test/groovy/io/emeraldpay/dshackle/upstream/ethereum/EthereumLocalReaderSpec.groovy index 1c36539c..1e046231 100644 --- a/src/test/groovy/io/emeraldpay/dshackle/upstream/ethereum/EthereumLocalReaderSpec.groovy +++ b/src/test/groovy/io/emeraldpay/dshackle/upstream/ethereum/EthereumLocalReaderSpec.groovy @@ -25,17 +25,16 @@ class EthereumLocalReaderSpec extends Specification { def "Calls hardcoded"() { setup: - def methods = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false) + def methods = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET) def router = new EthereumLocalReader( new EthereumCachingReader( TestingCommons.multistream(TestingCommons.api()), Caches.default(), - ConstantFactory.constantFactory(new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false)), + ConstantFactory.constantFactory(new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET)), TestingCommons.tracerMock() ), methods, new EmptyHead(), - null ) when: def act = router.read(new ChainRequest("eth_coinbase", new ListParams())).block(Duration.ofSeconds(1)) @@ -45,17 +44,16 @@ class EthereumLocalReaderSpec extends Specification { def "Returns empty if nonce set"() { setup: - def methods = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false) + def methods = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET) def router = new EthereumLocalReader( new EthereumCachingReader( TestingCommons.multistream(TestingCommons.api()), Caches.default(), - ConstantFactory.constantFactory(new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false)), + ConstantFactory.constantFactory(new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET)), TestingCommons.tracerMock() ), methods, new EmptyHead(), - null ) when: def act = router.read(new ChainRequest("eth_getTransactionByHash", new ListParams(["test"]), 10)) @@ -78,8 +76,8 @@ class EthereumLocalReaderSpec extends Specification { ) } } - def methods = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false) - def router = new EthereumLocalReader(reader, methods, head, null) + def methods = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET) + def router = new EthereumLocalReader(reader, methods, head) when: def act = router.getBlockByNumber(["latest", false], Selector.UpstreamFilter.default) @@ -106,8 +104,8 @@ class EthereumLocalReaderSpec extends Specification { ) } } - def methods = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false) - def router = new EthereumLocalReader(reader, methods, head, null) + def methods = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET) + def router = new EthereumLocalReader(reader, methods, head) when: def act = router.getBlockByNumber(["earliest", false], Selector.UpstreamFilter.default) @@ -134,8 +132,8 @@ class EthereumLocalReaderSpec extends Specification { ) } } - def methods = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false) - def router = new EthereumLocalReader(reader, methods, head, null) + def methods = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET) + def router = new EthereumLocalReader(reader, methods, head) when: def act = router.getBlockByNumber(["0x123ef", false], Selector.UpstreamFilter.default) @@ -160,8 +158,8 @@ class EthereumLocalReaderSpec extends Specification { ) } } - def methods = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false) - def router = new EthereumLocalReader(reader, methods, head, null) + def methods = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET) + def router = new EthereumLocalReader(reader, methods, head) when: def act = router.read( @@ -188,8 +186,8 @@ class EthereumLocalReaderSpec extends Specification { _ * txByHashAsCont(Selector.UpstreamFilter.default) >> new EmptyReader<>() _ * blocksByHeightAsCont(Selector.UpstreamFilter.default) >> new EmptyReader<>() } - def methods = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET, false) - def router = new EthereumLocalReader(reader, methods, head, null) + def methods = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET) + def router = new EthereumLocalReader(reader, methods, head) when: def act = router.getBlockByNumber(["0x0", true], Selector.UpstreamFilter.default) diff --git a/src/test/kotlin/io/emeraldpay/dshackle/config/reload/ReloadConfigTest.kt b/src/test/kotlin/io/emeraldpay/dshackle/config/reload/ReloadConfigTest.kt index 12c68651..69c6f40a 100644 --- a/src/test/kotlin/io/emeraldpay/dshackle/config/reload/ReloadConfigTest.kt +++ b/src/test/kotlin/io/emeraldpay/dshackle/config/reload/ReloadConfigTest.kt @@ -180,9 +180,6 @@ class ReloadConfigTest { cs.makeCachingReaderBuilder(mock()), cs::localReaderBuilder, cs.subscriptionBuilder(Schedulers.boundedElastic()), - null, - Schedulers.fromExecutor(Executors.newFixedThreadPool(6)), - mock(), ) }