From 02567c452a89b05e13b9a4051b81deead8916aff Mon Sep 17 00:00:00 2001 From: a10zn8 Date: Tue, 31 Oct 2023 01:04:05 +0300 Subject: [PATCH] ethereum as generic upstream - tests --- .../org/drpc/chainsconfig/ChainsConfig.kt | 10 ++- .../dshackle/upstream/Multistream.kt | 20 +++++ .../ethereum/EthereumChainSpecific.kt | 3 +- .../upstream/generic/GenericMultistream.kt | 21 ++++- .../upstream/generic/GenericUpstream.kt | 2 +- .../config/CacheConfigReaderSpec.groovy | 10 --- .../dshackle/rpc/NativeCallSpec.groovy | 7 +- .../test/MultistreamHolderMock.groovy | 11 ++- .../dshackle/test/TestingCommons.groovy | 18 ++++- .../dshackle/upstream/FilteredApisSpec.groovy | 3 +- .../dshackle/upstream/MultistreamSpec.groovy | 47 ++++++++--- .../ethereum/EthereumLocalReaderSpec.groovy | 14 ++-- .../EthereumUpstreamValidatorSpec.groovy | 77 ++++++++++--------- 13 files changed, 162 insertions(+), 81 deletions(-) diff --git a/foundation/src/main/kotlin/org/drpc/chainsconfig/ChainsConfig.kt b/foundation/src/main/kotlin/org/drpc/chainsconfig/ChainsConfig.kt index de74954e7..e043a2495 100644 --- a/foundation/src/main/kotlin/org/drpc/chainsconfig/ChainsConfig.kt +++ b/foundation/src/main/kotlin/org/drpc/chainsconfig/ChainsConfig.kt @@ -33,7 +33,10 @@ data class ChainsConfig(private val chains: List) : Iterable) : Iterable + Metrics.gauge( + "$metrics.availability", + listOf(Tag.of("chain", chain.chainCode), Tag.of("status", status.name.lowercase())), + this, + ) { + getAll().count { it.getStatus() == status }.toDouble() + } + } + + Metrics.gauge( + "$metrics.connected", + listOf(Tag.of("chain", chain.chainCode)), + this, + ) { + getAll().size.toDouble() + } + } + /** * Get list of all underlying upstreams */ 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 e28cfd720..217bb3807 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/ethereum/EthereumChainSpecific.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/ethereum/EthereumChainSpecific.kt @@ -41,7 +41,7 @@ object EthereumChainSpecific : ChainSpecific { override fun subscriptionBuilder(headScheduler: Scheduler): (Multistream) -> EgressSubscription { return { ms -> -// val pendingTxes: PendingTxesSource = (ms.upstreams as MutableList) +// val pendingTxes: PendingTxesSource = (ms.getAll()) // .mapNotNull { // it.getIngressSubscription().getPendingTxes() // }.let { @@ -54,6 +54,7 @@ object EthereumChainSpecific : ChainSpecific { // } // } // return + EmptyEgressSubscription } } 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 c6f481753..7fb8f0130 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/generic/GenericMultistream.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/generic/GenericMultistream.kt @@ -16,6 +16,7 @@ */ 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.UpstreamsConfig @@ -34,14 +35,16 @@ import io.emeraldpay.dshackle.upstream.Selector import io.emeraldpay.dshackle.upstream.Selector.Matcher import io.emeraldpay.dshackle.upstream.Upstream import io.emeraldpay.dshackle.upstream.forkchoice.PriorityForkChoice +import io.emeraldpay.dshackle.upstream.grpc.GrpcUpstream import org.springframework.util.ConcurrentReferenceHashMap import org.springframework.util.ConcurrentReferenceHashMap.ReferenceType.WEAK +import reactor.core.publisher.Flux import reactor.core.publisher.Mono import reactor.core.scheduler.Scheduler open class GenericMultistream( chain: Chain, - private val upstreams: MutableList, + private val upstreams: MutableList, caches: Caches, private val headScheduler: Scheduler, cachingReaderBuilder: CachingReaderBuilder, @@ -179,4 +182,20 @@ open class GenericMultistream( super.onUpstreamsUpdated() subscription = subscriptionBuilder(this) } + + override fun tryProxySubscribe( + matcher: Matcher, + request: BlockchainOuterClass.NativeSubscribeRequest, + ): Flux? = + upstreams.filter { + matcher.matches(it) + }.takeIf { ups -> + ups.size == 1 && ups.all { it.isGrpc() } + }?.map { + it as GrpcUpstream + }?.map { + it.proxySubscribe(request) + }?.let { + Flux.merge(it) + } } diff --git a/src/main/kotlin/io/emeraldpay/dshackle/upstream/generic/GenericUpstream.kt b/src/main/kotlin/io/emeraldpay/dshackle/upstream/generic/GenericUpstream.kt index d7de4af9a..5c5df67ef 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/upstream/generic/GenericUpstream.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/upstream/generic/GenericUpstream.kt @@ -50,7 +50,7 @@ open class GenericUpstream( private var validationSettingsSubscription: Disposable? = null private val hasLiveSubscriptionHead: AtomicBoolean = AtomicBoolean(false) - private val connector: GenericConnector = connectorFactory.create(this, chain, true) + protected val connector: GenericConnector = connectorFactory.create(this, chain, true) private var livenessSubscription: Disposable? = null private val labelsDetector = labelsDetectorBuilder(chain, this.getIngressReader()) diff --git a/src/test/groovy/io/emeraldpay/dshackle/config/CacheConfigReaderSpec.groovy b/src/test/groovy/io/emeraldpay/dshackle/config/CacheConfigReaderSpec.groovy index 9f6d962e3..99305cf9c 100644 --- a/src/test/groovy/io/emeraldpay/dshackle/config/CacheConfigReaderSpec.groovy +++ b/src/test/groovy/io/emeraldpay/dshackle/config/CacheConfigReaderSpec.groovy @@ -47,14 +47,4 @@ class CacheConfigReaderSpec extends Specification { //later may be not null if we support something else besides Redis act == null } - - def "Local read disabled"() { - setup: - def config = this.class.getClassLoader().getResourceAsStream("cache-local-router-disabled.yaml") - when: - def act = reader.read(config) - - then: - !act.requestsCacheEnabled - } } diff --git a/src/test/groovy/io/emeraldpay/dshackle/rpc/NativeCallSpec.groovy b/src/test/groovy/io/emeraldpay/dshackle/rpc/NativeCallSpec.groovy index 3f5bcec22..8ff0659cf 100644 --- a/src/test/groovy/io/emeraldpay/dshackle/rpc/NativeCallSpec.groovy +++ b/src/test/groovy/io/emeraldpay/dshackle/rpc/NativeCallSpec.groovy @@ -54,7 +54,7 @@ class NativeCallSpec extends Specification { ObjectMapper objectMapper = Global.objectMapper - def nativeCall(MultistreamHolder upstreams = null, ResponseSigner signer = null, Boolean enableCache = true, Boolean passthrough = false) { + def nativeCall(MultistreamHolder upstreams = null, ResponseSigner signer = null, Boolean passthrough = false) { if (upstreams == null) { upstreams = Stub(MultistreamHolder) @@ -65,7 +65,6 @@ class NativeCallSpec extends Specification { def config = new MainConfig() def cacheConfig = new CacheConfig() - cacheConfig.requestsCacheEnabled = enableCache config.cache = cacheConfig config.passthrough = passthrough @@ -77,7 +76,7 @@ class NativeCallSpec extends Specification { 1 * read(new JsonRpcRequest("eth_test", [])) >> Mono.just(new JsonRpcResponse("1".bytes, null)) } def upstream = Mock(Multistream) { - 1 * getLocalReader(_) >> Mono.just(routedApi) + 1 * getLocalReader() >> Mono.just(routedApi) } def nativeCall = nativeCall() @@ -98,7 +97,7 @@ class NativeCallSpec extends Specification { 1 * read(new JsonRpcRequest("eth_test", [])) >> Mono.error(new RpcException(RpcResponseError.CODE_METHOD_NOT_EXIST, "Test message")) } def upstream = Mock(Multistream) { - 1 * getLocalReader(_) >> Mono.just(routedApi) + 1 * getLocalReader() >> Mono.just(routedApi) } def nativeCall = nativeCall() diff --git a/src/test/groovy/io/emeraldpay/dshackle/test/MultistreamHolderMock.groovy b/src/test/groovy/io/emeraldpay/dshackle/test/MultistreamHolderMock.groovy index e80454d53..3eb64f582 100644 --- a/src/test/groovy/io/emeraldpay/dshackle/test/MultistreamHolderMock.groovy +++ b/src/test/groovy/io/emeraldpay/dshackle/test/MultistreamHolderMock.groovy @@ -26,6 +26,7 @@ import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinRpcUpstream import io.emeraldpay.dshackle.upstream.calls.CallMethods import io.emeraldpay.dshackle.upstream.calls.DefaultEthereumMethods import io.emeraldpay.dshackle.upstream.ethereum.EthereumCachingReader +import io.emeraldpay.dshackle.upstream.ethereum.EthereumChainSpecific import org.jetbrains.annotations.NotNull import org.springframework.cloud.sleuth.brave.bridge.BraveTracer import reactor.core.scheduler.Schedulers @@ -47,7 +48,10 @@ class MultistreamHolderMock implements MultistreamHolder { } else if (up instanceof GenericUpstream) { upstreams[chain] = new GenericMultistream( chain, [up as GenericUpstream], Caches.default(), - Schedulers.boundedElastic(), TestingCommons.tracerMock() + Schedulers.boundedElastic(), + EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(TestingCommons.tracerMock()), + EthereumChainSpecific.INSTANCE.&localReaderBuilder, + EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()) ) } else { throw new IllegalArgumentException("Unsupported upstream type ${up.class}") @@ -96,7 +100,10 @@ class MultistreamHolderMock implements MultistreamHolder { Head customHead = null EthereumMultistreamMock(@NotNull Chain chain, @NotNull List upstreams, @NotNull Caches caches) { - super(chain, upstreams, caches, Schedulers.boundedElastic(), new BraveTracer(null, null, null)) + super(chain, upstreams, caches, Schedulers.boundedElastic(), + EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(new BraveTracer(null, null, null)), + EthereumChainSpecific.INSTANCE.&localReaderBuilder, + 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 38e1363aa..80c73e397 100644 --- a/src/test/groovy/io/emeraldpay/dshackle/test/TestingCommons.groovy +++ b/src/test/groovy/io/emeraldpay/dshackle/test/TestingCommons.groovy @@ -31,6 +31,7 @@ import io.emeraldpay.dshackle.upstream.calls.DirectCallMethods import io.emeraldpay.dshackle.upstream.generic.GenericMultistream import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse +import io.emeraldpay.dshackle.upstream.ethereum.EthereumChainSpecific import io.emeraldpay.etherjar.domain.BlockHash import io.emeraldpay.dshackle.upstream.ethereum.json.BlockJson import io.emeraldpay.etherjar.domain.TransactionId @@ -90,7 +91,12 @@ class TestingCommons { } static Multistream multistream(GenericUpstreamMock up) { - return new EthereumMultistreamMock(Chain.ETHEREUM__MAINNET, [up], Caches.default(), Schedulers.boundedElastic(), tracerMock()).tap { + return new GenericMultistream(Chain.ETHEREUM__MAINNET, [up], Caches.default(), + Schedulers.boundedElastic(), + EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(tracerMock()), + EthereumChainSpecific.INSTANCE.&localReaderBuilder, + EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()), + ).tap { start() } } @@ -111,11 +117,17 @@ class TestingCommons { } static Multistream multistreamWithoutUpstreams(Chain chain) { - return new GenericMultistream(chain, [], emptyCaches().getCaches(chain), Schedulers.boundedElastic(), tracerMock()) + return new GenericMultistream(chain, [], emptyCaches().getCaches(chain), Schedulers.boundedElastic(), + EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(tracerMock()), + EthereumChainSpecific.INSTANCE.&localReaderBuilder, + EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic())) } static Multistream multistreamClassicWithoutUpstreams(Chain chain) { - return new GenericMultistream(chain, [], emptyCaches().getCaches(chain), Schedulers.boundedElastic(), tracerMock()) + return new GenericMultistream(chain, [], emptyCaches().getCaches(chain), Schedulers.boundedElastic(), + EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(tracerMock()), + EthereumChainSpecific.INSTANCE.&localReaderBuilder, + EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic())) } 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 74e234a19..780c849e2 100644 --- a/src/test/groovy/io/emeraldpay/dshackle/upstream/FilteredApisSpec.groovy +++ b/src/test/groovy/io/emeraldpay/dshackle/upstream/FilteredApisSpec.groovy @@ -68,15 +68,14 @@ class FilteredApisSpec extends Specification { ) new GenericUpstream( "test", - (byte) 123, Chain.ETHEREUM__MAINNET, + (byte) 123, new ChainOptions.PartialOptions().buildOptions(), UpstreamsConfig.UpstreamRole.PRIMARY, ethereumTargets, new QuorumForLabels.QuorumItem(1, UpstreamsConfig.Labels.fromMap(it)), ChainsConfig.ChainConfig.default(), connectorFactory, - false, null, cs.&validator, cs.&labelDetector, diff --git a/src/test/groovy/io/emeraldpay/dshackle/upstream/MultistreamSpec.groovy b/src/test/groovy/io/emeraldpay/dshackle/upstream/MultistreamSpec.groovy index 02b94d24b..c78496e64 100644 --- a/src/test/groovy/io/emeraldpay/dshackle/upstream/MultistreamSpec.groovy +++ b/src/test/groovy/io/emeraldpay/dshackle/upstream/MultistreamSpec.groovy @@ -28,6 +28,7 @@ import io.emeraldpay.dshackle.startup.UpstreamChangeEvent import io.emeraldpay.dshackle.test.GenericUpstreamMock import io.emeraldpay.dshackle.test.TestingCommons import io.emeraldpay.dshackle.upstream.calls.DirectCallMethods +import io.emeraldpay.dshackle.upstream.ethereum.EthereumChainSpecific import io.emeraldpay.dshackle.upstream.generic.GenericUpstream import io.emeraldpay.dshackle.upstream.generic.GenericMultistream import io.emeraldpay.dshackle.upstream.ethereum.json.BlockJson @@ -53,7 +54,11 @@ class MultistreamSpec extends Specification { setup: def up1 = new GenericUpstreamMock("test1", Chain.ETHEREUM__MAINNET, TestingCommons.api(), new DirectCallMethods(["eth_test1", "eth_test2"])) def up2 = new GenericUpstreamMock("test1", Chain.ETHEREUM__MAINNET, TestingCommons.api(), new DirectCallMethods(["eth_test2", "eth_test3"])) - def aggr = new GenericMultistream(Chain.ETHEREUM__MAINNET, [up1, up2], Caches.default(), Schedulers.boundedElastic(), TestingCommons.tracerMock()) + def aggr = new GenericMultistream(Chain.ETHEREUM__MAINNET, [up1, up2], Caches.default(), + Schedulers.boundedElastic(), + EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(TestingCommons.tracerMock()), + EthereumChainSpecific.INSTANCE.&localReaderBuilder, + EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic())) when: aggr.onUpstreamsUpdated() def act = aggr.getMethods() @@ -184,7 +189,11 @@ class MultistreamSpec extends Specification { def up1 = TestingCommons.upstream("test-1", "internal") def up2 = TestingCommons.upstream("test-2", "external") def up3 = TestingCommons.upstream("test-3", "external") - def multistream = new GenericMultistream(Chain.ETHEREUM__MAINNET, [up1, up2, up3], Caches.default(), Schedulers.boundedElastic(), TestingCommons.tracerMock()) + def multistream = new GenericMultistream(Chain.ETHEREUM__MAINNET, [up1, up2, up3], Caches.default(), + Schedulers.boundedElastic(), + EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(TestingCommons.tracerMock()), + EthereumChainSpecific.INSTANCE.&localReaderBuilder, + EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic())) expect: multistream.getHead(new Selector.LabelMatcher("provider", ["internal"])).is(up1.ethereumHeadMock) @@ -207,12 +216,12 @@ class MultistreamSpec extends Specification { def up1 = Mock(GenericGrpcUpstream) { 1 * isGrpc() >> true - 1 * getId() >> "internal" + _ * getId() >> "internal" 1 * getLabels() >> [UpstreamsConfig.Labels.fromMap(Collections.singletonMap("provider", "internal"))] 1 * proxySubscribe(call) >> Flux.just("{}") } - def up2 = Mock(GenericGrpcUpstream) { - 1 * getId() >> "external" + def up2 = Mock(GenericUpstream) { + _ * getId() >> "external" 1 * getLabels() >> [UpstreamsConfig.Labels.fromMap(Collections.singletonMap("provider", "external"))] } def multiStream = new TestEthereumPosMultistream(Chain.ETHEREUM__MAINNET, [up1, up2], Caches.default()) @@ -235,9 +244,9 @@ class MultistreamSpec extends Specification { .setMethod("newHeads") .build() - def up2 = Mock(GenericGrpcUpstream) { + def up2 = Mock(GenericUpstream) { 1 * isGrpc() >> false - 1 * getId() >> "2" + _ * getId() >> "2" 1 * getLabels() >> [UpstreamsConfig.Labels.fromMap(Collections.singletonMap("provider", "internal"))] } def multiStream = new TestEthereumPosMultistream(Chain.ETHEREUM__MAINNET, [up2], Caches.default()) @@ -253,7 +262,11 @@ class MultistreamSpec extends Specification { setup: def up1 = new GenericUpstreamMock("test1", Chain.ETHEREUM__MAINNET, TestingCommons.api(), new DirectCallMethods(["eth_test1", "eth_test2", "eth_test3"])) def up2 = new GenericUpstreamMock("test2", Chain.ETHEREUM__MAINNET, TestingCommons.api(), new DirectCallMethods(["eth_test1", "eth_test2"])) - def ms = new GenericMultistream(Chain.ETHEREUM__MAINNET, new ArrayList(), Caches.default(), Schedulers.boundedElastic(), TestingCommons.tracerMock()) + def ms = new GenericMultistream(Chain.ETHEREUM__MAINNET, new ArrayList(), Caches.default(), + Schedulers.boundedElastic(), + EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(TestingCommons.tracerMock()), + EthereumChainSpecific.INSTANCE.&localReaderBuilder, + EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic())) when: ms.onUpstreamChange( new UpstreamChangeEvent(Chain.ETHEREUM__MAINNET, up1, UpstreamChangeEvent.ChangeType.ADDED) @@ -280,7 +293,11 @@ class MultistreamSpec extends Specification { setup: def up1 = new GenericUpstreamMock("test1", Chain.ETHEREUM__MAINNET, TestingCommons.api(), new DirectCallMethods(["eth_test1", "eth_test2", "eth_test3"])) def up2 = new GenericUpstreamMock("test2", Chain.ETHEREUM__MAINNET, TestingCommons.api(), new DirectCallMethods(["eth_test1", "eth_test2"])) - def ms = new GenericMultistream(Chain.ETHEREUM__MAINNET, new ArrayList(), Caches.default(), Schedulers.boundedElastic(), TestingCommons.tracerMock()) + def ms = new GenericMultistream(Chain.ETHEREUM__MAINNET, new ArrayList(), Caches.default(), + Schedulers.boundedElastic(), + EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(TestingCommons.tracerMock()), + EthereumChainSpecific.INSTANCE.&localReaderBuilder, + EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic())) def head1 = createBlock(250, "0x0d050c785de17179f935b9b93aca09c442964cc59972c71ae68e74731448401b") def head2 = createBlock(270, "0x0d050c785de17179f935b9b93aca09c442964cc59972c71ae68e74731448402b") def head3 = createBlock(100, "0x0d050c785de17179f935b9b93aca09c442964cc59972c71ae68e74731448412b") @@ -311,7 +328,11 @@ class MultistreamSpec extends Specification { def up1 = TestingCommons.upstream("test-1", "internal") def up2 = TestingCommons.upstream("test-2", "external") def up3 = TestingCommons.upstream("test-3", "external") - def multistream = new GenericMultistream(Chain.ETHEREUM__MAINNET, [up1, up2, up3], Caches.default(), Schedulers.boundedElastic(), TestingCommons.tracerMock()) + def multistream = new GenericMultistream(Chain.ETHEREUM__MAINNET, [up1, up2, up3], Caches.default(), + Schedulers.boundedElastic(), + EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(TestingCommons.tracerMock()), + EthereumChainSpecific.INSTANCE.&localReaderBuilder, + EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic())) def observer = multistream.lagObserver multistream.onUpstreamsUpdated() @@ -338,7 +359,11 @@ class MultistreamSpec extends Specification { class TestEthereumPosMultistream extends GenericMultistream { TestEthereumPosMultistream(@NotNull Chain chain, @NotNull List upstreams, @NotNull Caches caches) { - super(chain, upstreams, caches, Schedulers.boundedElastic(), TestingCommons.tracerMock()) + super(chain, upstreams, caches, + Schedulers.boundedElastic(), + EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(TestingCommons.tracerMock()), + EthereumChainSpecific.INSTANCE.&localReaderBuilder, + EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic())) } @NotNull 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 7f37ce852..0807ce588 100644 --- a/src/test/groovy/io/emeraldpay/dshackle/upstream/ethereum/EthereumLocalReaderSpec.groovy +++ b/src/test/groovy/io/emeraldpay/dshackle/upstream/ethereum/EthereumLocalReaderSpec.groovy @@ -30,8 +30,7 @@ class EthereumLocalReaderSpec extends Specification { TestingCommons.tracerMock() ), methods, - new EmptyHead(), - true + new EmptyHead() ) when: def act = router.read(new JsonRpcRequest("eth_coinbase", [])).block(Duration.ofSeconds(1)) @@ -50,8 +49,7 @@ class EthereumLocalReaderSpec extends Specification { TestingCommons.tracerMock() ), methods, - new EmptyHead(), - true + new EmptyHead() ) when: def act = router.read(new JsonRpcRequest("eth_getTransactionByHash", ["test"], 10)) @@ -75,7 +73,7 @@ class EthereumLocalReaderSpec extends Specification { } } def methods = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET) - def router = new EthereumLocalReader(reader, methods, head, true) + def router = new EthereumLocalReader(reader, methods, head) when: def act = router.getBlockByNumber(["latest", false]) @@ -103,7 +101,7 @@ class EthereumLocalReaderSpec extends Specification { } } def methods = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET) - def router = new EthereumLocalReader(reader, methods, head, true) + def router = new EthereumLocalReader(reader, methods, head) when: def act = router.getBlockByNumber(["earliest", false]) @@ -131,7 +129,7 @@ class EthereumLocalReaderSpec extends Specification { } } def methods = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET) - def router = new EthereumLocalReader(reader, methods, head, true) + def router = new EthereumLocalReader(reader, methods, head) when: def act = router.getBlockByNumber(["0x123ef", false]) @@ -155,7 +153,7 @@ class EthereumLocalReaderSpec extends Specification { _ * blocksByHeightAsCont() >> new EmptyReader<>() } def methods = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET) - def router = new EthereumLocalReader(reader, methods, head, true) + def router = new EthereumLocalReader(reader, methods, head) when: def act = router.getBlockByNumber(["0x0", true]) diff --git a/src/test/groovy/io/emeraldpay/dshackle/upstream/ethereum/EthereumUpstreamValidatorSpec.groovy b/src/test/groovy/io/emeraldpay/dshackle/upstream/ethereum/EthereumUpstreamValidatorSpec.groovy index 4756c23d8..a65f23d8f 100644 --- a/src/test/groovy/io/emeraldpay/dshackle/upstream/ethereum/EthereumUpstreamValidatorSpec.groovy +++ b/src/test/groovy/io/emeraldpay/dshackle/upstream/ethereum/EthereumUpstreamValidatorSpec.groovy @@ -24,6 +24,7 @@ import io.emeraldpay.dshackle.upstream.Head import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcError import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse +import io.emeraldpay.dshackle.upstream.Upstream import io.emeraldpay.etherjar.domain.Address import io.emeraldpay.etherjar.hex.HexData import io.emeraldpay.etherjar.rpc.RpcResponseError @@ -41,12 +42,16 @@ import static io.emeraldpay.dshackle.upstream.ValidateUpstreamSettingsResult.UPS import static io.emeraldpay.dshackle.upstream.ValidateUpstreamSettingsResult.UPSTREAM_SETTINGS_ERROR import static io.emeraldpay.dshackle.upstream.ValidateUpstreamSettingsResult.UPSTREAM_VALID import static java.util.Collections.emptyList +import io.emeraldpay.dshackle.config.ChainsConfig.ChainConfig class EthereumUpstreamValidatorSpec extends Specification { + def conf = ChainConfig.defaultWithContract("0x32268860cAAc2948Ab5DdC7b20db5a420467Cf96") + def "Resolve to final availability"() { setup: - def validator = new EthereumUpstreamValidator(ETHEREUM__MAINNET, Stub(EthereumLikeUpstream), ChainOptions.PartialOptions.getDefaults().buildOptions()) + + def validator = new EthereumUpstreamValidator(ETHEREUM__MAINNET, Stub(Upstream), ChainOptions.PartialOptions.getDefaults().buildOptions(), conf) expect: validator.resolve(Tuples.of(sync, peers)) == exp where: @@ -67,8 +72,8 @@ class EthereumUpstreamValidatorSpec extends Specification { def options = ChainOptions.PartialOptions.getDefaults().tap { it.validateSyncing = false }.buildOptions() - def up = Mock(EthereumLikeUpstream) - def validator = new EthereumUpstreamValidator(ETHEREUM__MAINNET, up, options) + def up = Mock(Upstream) + def validator = new EthereumUpstreamValidator(ETHEREUM__MAINNET, up, options, conf) when: def act = validator.validateSyncing().block(Duration.ofSeconds(1)) @@ -87,7 +92,7 @@ class EthereumUpstreamValidatorSpec extends Specification { answer("eth_syncing", [], false) } ) - def validator = new EthereumUpstreamValidator(ETHEREUM__MAINNET, up, options) + def validator = new EthereumUpstreamValidator(ETHEREUM__MAINNET, up, options, conf) when: def act = validator.validateSyncing().block(Duration.ofSeconds(1)) @@ -100,7 +105,7 @@ class EthereumUpstreamValidatorSpec extends Specification { def options = ChainOptions.PartialOptions.getDefaults().tap { it.validateSyncing = true }.buildOptions() - def up = Mock(EthereumLikeUpstream) { + def up = Mock(Upstream) { 2 * getIngressReader() >> Mock(Reader) { reader -> 2 * reader.read(_) >>> [ Mono.just(new JsonRpcResponse('true'.getBytes(), null)), @@ -112,7 +117,7 @@ class EthereumUpstreamValidatorSpec extends Specification { 1 * head.onSyncingNode(false) } } - def validator = new EthereumUpstreamValidator(ETHEREUM__MAINNET, up, options) + def validator = new EthereumUpstreamValidator(ETHEREUM__MAINNET, up, options, conf) when: def act = validator.validateSyncing().block(Duration.ofSeconds(1)) @@ -132,7 +137,7 @@ class EthereumUpstreamValidatorSpec extends Specification { answer("eth_syncing", [], [startingBlock: 100, currentBlock: 50]) } ) - def validator = new EthereumUpstreamValidator(ETHEREUM__MAINNET, up, options) + def validator = new EthereumUpstreamValidator(ETHEREUM__MAINNET, up, options, conf) when: def act = validator.validateSyncing().block(Duration.ofSeconds(1)) @@ -150,7 +155,7 @@ class EthereumUpstreamValidatorSpec extends Specification { answer("eth_syncing", [], new RpcResponseError(RpcResponseError.CODE_METHOD_NOT_EXIST, "Unavailable")) } ) - def validator = new EthereumUpstreamValidator(ETHEREUM__MAINNET, up, options) + def validator = new EthereumUpstreamValidator(ETHEREUM__MAINNET, up, options, conf) when: def act = validator.validateSyncing().block(Duration.ofSeconds(1)) @@ -164,8 +169,8 @@ class EthereumUpstreamValidatorSpec extends Specification { it.validatePeers = false it.minPeers = 10 }.buildOptions() - def up = Mock(EthereumLikeUpstream) - def validator = new EthereumUpstreamValidator(ETHEREUM__MAINNET, up, options) + def up = Mock(Upstream) + def validator = new EthereumUpstreamValidator(ETHEREUM__MAINNET, up, options, conf) when: def act = validator.validatePeers().block(Duration.ofSeconds(1)) @@ -180,8 +185,8 @@ class EthereumUpstreamValidatorSpec extends Specification { it.validatePeers = true it.minPeers = 0 }.buildOptions() - def up = Mock(EthereumLikeUpstream) - def validator = new EthereumUpstreamValidator(ETHEREUM__MAINNET, up, options) + def up = Mock(Upstream) + def validator = new EthereumUpstreamValidator(ETHEREUM__MAINNET, up, options, conf) when: def act = validator.validatePeers().block(Duration.ofSeconds(1)) @@ -201,7 +206,7 @@ class EthereumUpstreamValidatorSpec extends Specification { answer("net_peerCount", [], "0x5") } ) - def validator = new EthereumUpstreamValidator(ETHEREUM__MAINNET, up, options) + def validator = new EthereumUpstreamValidator(ETHEREUM__MAINNET, up, options, conf) when: def act = validator.validatePeers().block(Duration.ofSeconds(1)) @@ -220,7 +225,7 @@ class EthereumUpstreamValidatorSpec extends Specification { answer("net_peerCount", [], "0xa") } ) - def validator = new EthereumUpstreamValidator(ETHEREUM__MAINNET, up, options) + def validator = new EthereumUpstreamValidator(ETHEREUM__MAINNET, up, options, conf) when: def act = validator.validatePeers().block(Duration.ofSeconds(1)) @@ -239,7 +244,7 @@ class EthereumUpstreamValidatorSpec extends Specification { answer("net_peerCount", [], "0xff") } ) - def validator = new EthereumUpstreamValidator(ETHEREUM__MAINNET, up, options) + def validator = new EthereumUpstreamValidator(ETHEREUM__MAINNET, up, options, conf) when: def act = validator.validatePeers().block(Duration.ofSeconds(1)) @@ -258,7 +263,7 @@ class EthereumUpstreamValidatorSpec extends Specification { answer("net_peerCount", [], new RpcResponseError(RpcResponseError.CODE_METHOD_NOT_EXIST, "Unavailable")) } ) - def validator = new EthereumUpstreamValidator(ETHEREUM__MAINNET, up, options) + def validator = new EthereumUpstreamValidator(ETHEREUM__MAINNET, up, options, conf) when: def act = validator.validatePeers().block(Duration.ofSeconds(1)) @@ -272,7 +277,7 @@ class EthereumUpstreamValidatorSpec extends Specification { it.validateCalllimit = false it.validateChain = false }.buildOptions() - def up = Mock(EthereumLikeUpstream) { + def up = Mock(Upstream) { 2 * getIngressReader() >> Mock(Reader) { 1 * read(new JsonRpcRequest("eth_blockNumber", [])) >> Mono.just(new JsonRpcResponse('"0x10ff9be"'.getBytes(), null)) @@ -280,7 +285,7 @@ class EthereumUpstreamValidatorSpec extends Specification { Mono.just(new JsonRpcResponse('"result"'.getBytes(), null)) } } - def validator = new EthereumUpstreamValidator(ETHEREUM__MAINNET, up, options) + def validator = new EthereumUpstreamValidator(ETHEREUM__MAINNET, up, options, conf) when: def act = validator.validateUpstreamSettingsOnStartup() @@ -293,7 +298,7 @@ class EthereumUpstreamValidatorSpec extends Specification { def options = ChainOptions.PartialOptions.getDefaults().tap { it.validateChain = false }.buildOptions() - def up = Mock(EthereumLikeRpcUpstream) { + def up = Mock(Upstream) { 3 * getIngressReader() >> Mock(Reader) { 1 * read(new JsonRpcRequest("eth_call", [new TransactionCallJson( Address.from("0x32268860cAAc2948Ab5DdC7b20db5a420467Cf96"), @@ -304,8 +309,8 @@ class EthereumUpstreamValidatorSpec extends Specification { Mono.just(new JsonRpcResponse('"result"'.getBytes(), null)) } } - def validator = new EthereumUpstreamValidator(ETHEREUM__MAINNET, up, options, "0x32268860cAAc2948Ab5DdC7b20db5a420467Cf96") - + def validator = new EthereumUpstreamValidator(ETHEREUM__MAINNET, up, options, conf) +//"0x32268860cAAc2948Ab5DdC7b20db5a420467Cf96 when: def act = validator.validateUpstreamSettingsOnStartup() then: @@ -317,7 +322,7 @@ class EthereumUpstreamValidatorSpec extends Specification { def options = ChainOptions.PartialOptions.getDefaults().tap { it.validateChain = false }.buildOptions() - def up = Mock(EthereumLikeRpcUpstream) { + def up = Mock(Upstream) { 3 * getIngressReader() >> Mock(Reader) { 1 * read(new JsonRpcRequest("eth_call", [new TransactionCallJson( Address.from("0x32268860cAAc2948Ab5DdC7b20db5a420467Cf96"), @@ -328,8 +333,8 @@ class EthereumUpstreamValidatorSpec extends Specification { Mono.just(new JsonRpcResponse('"result"'.getBytes(), null)) } } - def validator = new EthereumUpstreamValidator(ETHEREUM__MAINNET, up, options, "0x32268860cAAc2948Ab5DdC7b20db5a420467Cf96") - + def validator = new EthereumUpstreamValidator(ETHEREUM__MAINNET, up, options, conf) +// "0x32268860cAAc2948Ab5DdC7b20db5a420467Cf96" when: def act = validator.validateUpstreamSettingsOnStartup() then: @@ -341,7 +346,7 @@ class EthereumUpstreamValidatorSpec extends Specification { def options = ChainOptions.PartialOptions.getDefaults().tap { it.validateCalllimit = false }.buildOptions() - def up = Mock(EthereumLikeRpcUpstream) { + def up = Mock(Upstream) { 4 * getIngressReader() >> Mock(Reader) { 1 * read(new JsonRpcRequest("eth_chainId", emptyList())) >> Mono.just(new JsonRpcResponse('"0x1"'.getBytes(), null)) 1 * read(new JsonRpcRequest("net_version", emptyList())) >> Mono.just(new JsonRpcResponse('"1"'.getBytes(), null)) @@ -350,8 +355,8 @@ class EthereumUpstreamValidatorSpec extends Specification { Mono.just(new JsonRpcResponse('"result"'.getBytes(), null)) } } - def validator = new EthereumUpstreamValidator(ETHEREUM__MAINNET, up, options, "0x32268860cAAc2948Ab5DdC7b20db5a420467Cf96") - + def validator = new EthereumUpstreamValidator(ETHEREUM__MAINNET, up, options, conf) +// "0x32268860cAAc2948Ab5DdC7b20db5a420467Cf96" when: def act = validator.validateUpstreamSettingsOnStartup() then: @@ -363,7 +368,7 @@ class EthereumUpstreamValidatorSpec extends Specification { def options = ChainOptions.PartialOptions.getDefaults().tap { it.validateCalllimit = false }.buildOptions() - def up = Mock(EthereumLikeRpcUpstream) { + def up = Mock(Upstream) { 4 * getIngressReader() >> Mock(Reader) { 1 * read(new JsonRpcRequest("eth_chainId", emptyList())) >> Mono.just(new JsonRpcResponse('"0x1"'.getBytes(), null)) 1 * read(new JsonRpcRequest("net_version", emptyList())) >> Mono.just(new JsonRpcResponse('"1"'.getBytes(), null)) @@ -372,8 +377,8 @@ class EthereumUpstreamValidatorSpec extends Specification { Mono.just(new JsonRpcResponse('"result"'.getBytes(), null)) } } - def validator = new EthereumUpstreamValidator(OPTIMISM__MAINNET, up, options, "0x32268860cAAc2948Ab5DdC7b20db5a420467Cf96") - + def validator = new EthereumUpstreamValidator(OPTIMISM__MAINNET, up, options, conf) +// "0x32268860cAAc2948Ab5DdC7b20db5a420467Cf96" when: def act = validator.validateUpstreamSettingsOnStartup() then: @@ -383,7 +388,7 @@ class EthereumUpstreamValidatorSpec extends Specification { def "Upstream is valid if all setting are valid"() { setup: def options = ChainOptions.PartialOptions.getDefaults().buildOptions() - def up = Mock(EthereumLikeRpcUpstream) { + def up = Mock(Upstream) { 5 * getIngressReader() >> Mock(Reader) { 1 * read(new JsonRpcRequest("eth_chainId", emptyList())) >> Mono.just(new JsonRpcResponse('"0x1"'.getBytes(), null)) 1 * read(new JsonRpcRequest("net_version", emptyList())) >> Mono.just(new JsonRpcResponse('"1"'.getBytes(), null)) @@ -396,8 +401,8 @@ class EthereumUpstreamValidatorSpec extends Specification { Mono.just(new JsonRpcResponse('"result"'.getBytes(), null)) } } - def validator = new EthereumUpstreamValidator(ETHEREUM__MAINNET, up, options, "0x32268860cAAc2948Ab5DdC7b20db5a420467Cf96") - + def validator = new EthereumUpstreamValidator(ETHEREUM__MAINNET, up, options, conf) +// "0x32268860cAAc2948Ab5DdC7b20db5a420467Cf96" when: def act = validator.validateUpstreamSettingsOnStartup() then: @@ -407,7 +412,7 @@ class EthereumUpstreamValidatorSpec extends Specification { def "Upstream is not valid if there are errors"() { setup: def options = ChainOptions.PartialOptions.getDefaults().buildOptions() - def up = Mock(EthereumLikeRpcUpstream) { + def up = Mock(Upstream) { 5 * getIngressReader() >> Mock(Reader) { 1 * read(new JsonRpcRequest("eth_chainId", emptyList())) >> Mono.just(new JsonRpcResponse(null, new JsonRpcError(1, "Too long"))) 1 * read(new JsonRpcRequest("net_version", emptyList())) >> Mono.just(new JsonRpcResponse(null, new JsonRpcError(1, "Too long"))) @@ -420,8 +425,8 @@ class EthereumUpstreamValidatorSpec extends Specification { Mono.just(new JsonRpcResponse('"result"'.getBytes(), null)) } } - def validator = new EthereumUpstreamValidator(ETHEREUM__MAINNET, up, options, "0x32268860cAAc2948Ab5DdC7b20db5a420467Cf96") - + def validator = new EthereumUpstreamValidator(ETHEREUM__MAINNET, up, options, conf) +// "0x32268860cAAc2948Ab5DdC7b20db5a420467Cf96" when: def act = validator.validateUpstreamSettingsOnStartup() then: