ethereum as generic upstream (#331)
- merge all Ethereum implementations to Generic upstreams and multistreams - merge evm-pos and pow to ethereum
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -21,7 +21,7 @@ import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.test.MultistreamHolderMock
|
||||
import io.emeraldpay.dshackle.upstream.Selector
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumEgressSubscription
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumPosMultiStream
|
||||
import io.emeraldpay.dshackle.upstream.generic.GenericMultistream
|
||||
import io.emeraldpay.dshackle.upstream.signature.NoSigner
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.test.StepVerifier
|
||||
@@ -42,7 +42,7 @@ class NativeSubscribeSpec extends Specification {
|
||||
def subscribe = Mock(EthereumEgressSubscription) {
|
||||
1 * it.subscribe("newHeads", null, _ as Selector.AnyLabelMatcher) >> Flux.just("{}")
|
||||
}
|
||||
def up = Mock(EthereumPosMultiStream) {
|
||||
def up = Mock(GenericMultistream) {
|
||||
1 * it.tryProxySubscribe(_ as Selector.AnyLabelMatcher, call) >> null
|
||||
1 * it.getEgressSubscription() >> subscribe
|
||||
}
|
||||
@@ -81,7 +81,7 @@ class NativeSubscribeSpec extends Specification {
|
||||
ok
|
||||
}, _ as Selector.AnyLabelMatcher) >> Flux.just("{}")
|
||||
}
|
||||
def up = Mock(EthereumPosMultiStream) {
|
||||
def up = Mock(GenericMultistream) {
|
||||
1 * it.tryProxySubscribe(_ as Selector.AnyLabelMatcher, call) >> null
|
||||
1 * it.getEgressSubscription() >> subscribe
|
||||
}
|
||||
@@ -104,7 +104,7 @@ class NativeSubscribeSpec extends Specification {
|
||||
.setChainValue(Chain.ETHEREUM__MAINNET.id)
|
||||
.setMethod("newHeads")
|
||||
.build()
|
||||
def up = Mock(EthereumPosMultiStream) {
|
||||
def up = Mock(GenericMultistream) {
|
||||
1 * it.tryProxySubscribe(_ as Selector.AnyLabelMatcher, call) >> Flux.just("{}")
|
||||
0 * it.getEgressSubscription()
|
||||
}
|
||||
|
||||
@@ -16,17 +16,15 @@
|
||||
*/
|
||||
package io.emeraldpay.dshackle.rpc
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.google.protobuf.ByteString
|
||||
import io.emeraldpay.api.proto.BlockchainOuterClass
|
||||
import io.emeraldpay.api.proto.Common
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.Global
|
||||
import io.emeraldpay.dshackle.data.BlockContainer
|
||||
import io.emeraldpay.dshackle.test.EthereumPosRpcUpstreamMock
|
||||
import io.emeraldpay.dshackle.upstream.generic.GenericUpstream
|
||||
import io.emeraldpay.dshackle.test.GenericUpstreamMock
|
||||
import io.emeraldpay.dshackle.test.MultistreamHolderMock
|
||||
import io.emeraldpay.dshackle.test.TestingCommons
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumLikeRpcUpstream
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.json.BlockJson
|
||||
import io.emeraldpay.etherjar.domain.BlockHash
|
||||
import io.emeraldpay.etherjar.rpc.json.TransactionRefJson
|
||||
@@ -39,11 +37,9 @@ import java.time.Instant
|
||||
|
||||
class StreamHeadSpec extends Specification {
|
||||
|
||||
ObjectMapper objectMapper = Global.objectMapper
|
||||
|
||||
def "Errors on unavailable chain"() {
|
||||
setup:
|
||||
def upstreams = new MultistreamHolderMock(Chain.ETHEREUM__MAINNET, Stub(EthereumLikeRpcUpstream))
|
||||
def upstreams = new MultistreamHolderMock(Chain.ETHEREUM__MAINNET, Stub(GenericUpstream))
|
||||
def streamHead = new StreamHead(upstreams)
|
||||
when:
|
||||
def flux = streamHead.add(
|
||||
@@ -80,7 +76,7 @@ class StreamHeadSpec extends Specification {
|
||||
.build()
|
||||
}
|
||||
|
||||
def upstream = new EthereumPosRpcUpstreamMock(Chain.ETHEREUM__MAINNET, TestingCommons.api())
|
||||
def upstream = new GenericUpstreamMock(Chain.ETHEREUM__MAINNET, TestingCommons.api())
|
||||
def upstreams = new MultistreamHolderMock(Chain.ETHEREUM__MAINNET, upstream)
|
||||
def streamHead = new StreamHead(upstreams)
|
||||
when:
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2019 ETCDEV GmbH
|
||||
* Copyright (c) 2020 EmeraldPay, Inc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.emeraldpay.dshackle.test
|
||||
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.config.ChainsConfig
|
||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||
import io.emeraldpay.dshackle.data.BlockContainer
|
||||
import io.emeraldpay.dshackle.reader.Reader
|
||||
import io.emeraldpay.dshackle.startup.QuorumForLabels
|
||||
import io.emeraldpay.dshackle.upstream.UpstreamAvailability
|
||||
import io.emeraldpay.dshackle.upstream.calls.*
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumLikeRpcUpstream
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
|
||||
import org.jetbrains.annotations.NotNull
|
||||
import io.emeraldpay.dshackle.foundation.ChainOptions
|
||||
import org.reactivestreams.Publisher
|
||||
|
||||
class EthereumRpcUpstreamMock extends EthereumLikeRpcUpstream {
|
||||
EthereumHeadMock ethereumHeadMock
|
||||
|
||||
|
||||
static CallMethods allMethods() {
|
||||
new AggregatedCallMethods([
|
||||
new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET),
|
||||
new DefaultBitcoinMethods(),
|
||||
new DirectCallMethods(["eth_test"])
|
||||
])
|
||||
}
|
||||
|
||||
EthereumRpcUpstreamMock(@NotNull Chain chain, @NotNull Reader<JsonRpcRequest, JsonRpcResponse> api) {
|
||||
this(chain, api, allMethods())
|
||||
}
|
||||
|
||||
EthereumRpcUpstreamMock(@NotNull String id, @NotNull Chain chain, @NotNull Reader<JsonRpcRequest, JsonRpcResponse> api) {
|
||||
this(id, chain, api, allMethods())
|
||||
}
|
||||
|
||||
EthereumRpcUpstreamMock(@NotNull Chain chain, @NotNull Reader<JsonRpcRequest, JsonRpcResponse> api, CallMethods methods) {
|
||||
this("test", chain, api, methods)
|
||||
}
|
||||
|
||||
EthereumRpcUpstreamMock(@NotNull String id, @NotNull Chain chain, @NotNull Reader<JsonRpcRequest, JsonRpcResponse> api, CallMethods methods) {
|
||||
super(id, id.hashCode().byteValue(), chain,
|
||||
ChainOptions.PartialOptions.getDefaults().buildOptions(),
|
||||
UpstreamsConfig.UpstreamRole.PRIMARY,
|
||||
methods,
|
||||
new QuorumForLabels.QuorumItem(1, new UpstreamsConfig.Labels()),
|
||||
new ConnectorFactoryMock(api, new EthereumHeadMock()),
|
||||
ChainsConfig.ChainConfig.default(),
|
||||
false,
|
||||
null
|
||||
)
|
||||
this.ethereumHeadMock = this.getHead() as EthereumHeadMock
|
||||
setLag(0)
|
||||
setStatus(UpstreamAvailability.OK)
|
||||
start()
|
||||
}
|
||||
|
||||
void nextBlock(BlockContainer block) {
|
||||
this.ethereumHeadMock.nextBlock(block)
|
||||
}
|
||||
|
||||
void setBlocks(Publisher<BlockContainer> blocks) {
|
||||
this.ethereumHeadMock.predefined = blocks
|
||||
}
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
return "Upstream mock ${getId()}"
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ package io.emeraldpay.dshackle.test
|
||||
|
||||
import io.emeraldpay.dshackle.reader.Reader
|
||||
import io.emeraldpay.dshackle.upstream.Head
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumIngressSubscription
|
||||
import io.emeraldpay.dshackle.upstream.IngressSubscription
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.NoEthereumIngressSubscription
|
||||
import io.emeraldpay.dshackle.upstream.generic.connectors.GenericConnector
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
||||
@@ -47,7 +47,7 @@ class GenericConnectorMock implements GenericConnector {
|
||||
}
|
||||
|
||||
@Override
|
||||
EthereumIngressSubscription getIngressSubscription() {
|
||||
IngressSubscription getIngressSubscription() {
|
||||
return NoEthereumIngressSubscription.DEFAULT
|
||||
}
|
||||
}
|
||||
@@ -24,14 +24,14 @@ import io.emeraldpay.dshackle.reader.Reader
|
||||
import io.emeraldpay.dshackle.startup.QuorumForLabels
|
||||
import io.emeraldpay.dshackle.upstream.UpstreamAvailability
|
||||
import io.emeraldpay.dshackle.upstream.calls.*
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumLikeRpcUpstream
|
||||
import io.emeraldpay.dshackle.upstream.generic.GenericUpstream
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
|
||||
import org.jetbrains.annotations.NotNull
|
||||
import org.reactivestreams.Publisher
|
||||
import io.emeraldpay.dshackle.foundation.ChainOptions
|
||||
|
||||
class EthereumPosRpcUpstreamMock extends EthereumLikeRpcUpstream {
|
||||
class GenericUpstreamMock extends GenericUpstream {
|
||||
EthereumHeadMock ethereumHeadMock
|
||||
|
||||
static CallMethods allMethods() {
|
||||
@@ -42,36 +42,40 @@ class EthereumPosRpcUpstreamMock extends EthereumLikeRpcUpstream {
|
||||
])
|
||||
}
|
||||
|
||||
EthereumPosRpcUpstreamMock(@NotNull Chain chain, @NotNull Reader<JsonRpcRequest, JsonRpcResponse> api) {
|
||||
GenericUpstreamMock(@NotNull Chain chain, @NotNull Reader<JsonRpcRequest, JsonRpcResponse> api) {
|
||||
this(chain, api, allMethods())
|
||||
}
|
||||
|
||||
EthereumPosRpcUpstreamMock(@NotNull String id, @NotNull Chain chain, @NotNull Reader<JsonRpcRequest, JsonRpcResponse> api, Map<String, String> labels) {
|
||||
GenericUpstreamMock(@NotNull String id, @NotNull Chain chain, @NotNull Reader<JsonRpcRequest, JsonRpcResponse> api, Map<String, String> labels) {
|
||||
this(id, chain, api, allMethods(), labels)
|
||||
}
|
||||
|
||||
EthereumPosRpcUpstreamMock(@NotNull String id, @NotNull Chain chain, @NotNull Reader<JsonRpcRequest, JsonRpcResponse> api) {
|
||||
GenericUpstreamMock(@NotNull String id, @NotNull Chain chain, @NotNull Reader<JsonRpcRequest, JsonRpcResponse> api) {
|
||||
this(id, chain, api, allMethods())
|
||||
}
|
||||
|
||||
EthereumPosRpcUpstreamMock(@NotNull Chain chain, @NotNull Reader<JsonRpcRequest, JsonRpcResponse> api, CallMethods methods) {
|
||||
GenericUpstreamMock(@NotNull Chain chain, @NotNull Reader<JsonRpcRequest, JsonRpcResponse> api, CallMethods methods) {
|
||||
this("test", chain, api, methods)
|
||||
}
|
||||
|
||||
EthereumPosRpcUpstreamMock(@NotNull String id, @NotNull Chain chain, @NotNull Reader<JsonRpcRequest, JsonRpcResponse> api, CallMethods methods) {
|
||||
GenericUpstreamMock(@NotNull String id, @NotNull Chain chain, @NotNull Reader<JsonRpcRequest, JsonRpcResponse> api, CallMethods methods) {
|
||||
this(id, chain, api, methods, Collections.<String, String>emptyMap())
|
||||
}
|
||||
|
||||
EthereumPosRpcUpstreamMock(@NotNull String id, @NotNull Chain chain, @NotNull Reader<JsonRpcRequest, JsonRpcResponse> api, CallMethods methods, Map<String, String> labels) {
|
||||
super(id, (byte)id.hashCode(), chain,
|
||||
GenericUpstreamMock(@NotNull String id, @NotNull Chain chain, @NotNull Reader<JsonRpcRequest, JsonRpcResponse> api, CallMethods methods, Map<String, String> labels) {
|
||||
super(id,
|
||||
chain,
|
||||
(byte)id.hashCode(),
|
||||
getOpts(),
|
||||
UpstreamsConfig.UpstreamRole.PRIMARY,
|
||||
methods,
|
||||
new QuorumForLabels.QuorumItem(1, UpstreamsConfig.Labels.fromMap(labels)),
|
||||
new ConnectorFactoryMock(api, new EthereumHeadMock()),
|
||||
ChainConfig.default(),
|
||||
true,
|
||||
null
|
||||
new ConnectorFactoryMock(api, new EthereumHeadMock()),
|
||||
null,
|
||||
io.emeraldpay.dshackle.upstream.starknet.StarknetChainSpecific.INSTANCE.&validator,
|
||||
io.emeraldpay.dshackle.upstream.starknet.StarknetChainSpecific.INSTANCE.&labelDetector,
|
||||
io.emeraldpay.dshackle.upstream.starknet.StarknetChainSpecific.INSTANCE.&subscriptionTopics,
|
||||
)
|
||||
this.ethereumHeadMock = this.getHead() as EthereumHeadMock
|
||||
setLag(0)
|
||||
@@ -20,13 +20,13 @@ import io.emeraldpay.dshackle.BlockchainType
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.cache.Caches
|
||||
import io.emeraldpay.dshackle.upstream.*
|
||||
import io.emeraldpay.dshackle.upstream.generic.*
|
||||
import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinMultistream
|
||||
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.EthereumLikeRpcUpstream
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumPosMultiStream
|
||||
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
|
||||
@@ -42,13 +42,16 @@ class MultistreamHolderMock implements MultistreamHolder {
|
||||
|
||||
Multistream addUpstream(@NotNull Chain chain, @NotNull Upstream up) {
|
||||
if (!upstreams.containsKey(chain)) {
|
||||
if (BlockchainType.from(chain) == BlockchainType.EVM_POS) {
|
||||
if (up instanceof EthereumPosMultiStream) {
|
||||
if (BlockchainType.from(chain) == BlockchainType.ETHEREUM) {
|
||||
if (up instanceof GenericMultistream) {
|
||||
upstreams[chain] = up
|
||||
} else if (up instanceof EthereumLikeRpcUpstream) {
|
||||
upstreams[chain] = new EthereumPosMultiStream(
|
||||
chain, [up as EthereumLikeRpcUpstream], Caches.default(),
|
||||
Schedulers.boundedElastic(), TestingCommons.tracerMock()
|
||||
} else if (up instanceof GenericUpstream) {
|
||||
upstreams[chain] = new GenericMultistream(
|
||||
chain, [up as GenericUpstream], Caches.default(),
|
||||
Schedulers.boundedElastic(),
|
||||
EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(TestingCommons.tracerMock()),
|
||||
EthereumChainSpecific.INSTANCE.&localReaderBuilder,
|
||||
io.emeraldpay.dshackle.upstream.starknet.StarknetChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic())
|
||||
)
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported upstream type ${up.class}")
|
||||
@@ -90,21 +93,24 @@ class MultistreamHolderMock implements MultistreamHolder {
|
||||
return upstreams.values().toList()
|
||||
}
|
||||
|
||||
static class EthereumMultistreamMock extends EthereumPosMultiStream {
|
||||
static class EthereumMultistreamMock extends GenericMultistream {
|
||||
|
||||
EthereumCachingReader customReader = null
|
||||
CallMethods customMethods = null
|
||||
Head customHead = null
|
||||
|
||||
EthereumMultistreamMock(@NotNull Chain chain, @NotNull List<EthereumLikeRpcUpstream> upstreams, @NotNull Caches caches) {
|
||||
super(chain, upstreams, caches, Schedulers.boundedElastic(), new BraveTracer(null, null, null))
|
||||
EthereumMultistreamMock(@NotNull Chain chain, @NotNull List<GenericUpstream> upstreams, @NotNull Caches caches) {
|
||||
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<EthereumLikeRpcUpstream> upstreams) {
|
||||
EthereumMultistreamMock(@NotNull Chain chain, @NotNull List<GenericUpstream> upstreams) {
|
||||
this(chain, upstreams, Caches.default())
|
||||
}
|
||||
|
||||
EthereumMultistreamMock(@NotNull Chain chain, @NotNull EthereumLikeRpcUpstream upstream) {
|
||||
EthereumMultistreamMock(@NotNull Chain chain, @NotNull GenericUpstream upstream) {
|
||||
this(chain, [upstream])
|
||||
}
|
||||
|
||||
|
||||
@@ -28,10 +28,10 @@ import io.emeraldpay.dshackle.reader.Reader
|
||||
import io.emeraldpay.dshackle.upstream.Multistream
|
||||
import io.emeraldpay.dshackle.upstream.calls.CallMethods
|
||||
import io.emeraldpay.dshackle.upstream.calls.DirectCallMethods
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumMultistream
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumPosMultiStream
|
||||
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
|
||||
@@ -54,44 +54,49 @@ class TestingCommons {
|
||||
return new TracerMock(null, null, null)
|
||||
}
|
||||
|
||||
static EthereumPosRpcUpstreamMock upstream() {
|
||||
return new EthereumPosRpcUpstreamMock(Chain.ETHEREUM__MAINNET, api())
|
||||
static GenericUpstreamMock upstream() {
|
||||
return new GenericUpstreamMock(Chain.ETHEREUM__MAINNET, api())
|
||||
}
|
||||
|
||||
static EthereumPosRpcUpstreamMock upstream(String id) {
|
||||
return new EthereumPosRpcUpstreamMock(id, Chain.ETHEREUM__MAINNET, api())
|
||||
static GenericUpstreamMock upstream(String id) {
|
||||
return new GenericUpstreamMock(id, Chain.ETHEREUM__MAINNET, api())
|
||||
}
|
||||
|
||||
static EthereumPosRpcUpstreamMock upstream(String id, String provider) {
|
||||
return new EthereumPosRpcUpstreamMock(id, Chain.ETHEREUM__MAINNET, api(), Collections.singletonMap("provider", provider))
|
||||
static GenericUpstreamMock upstream(String id, String provider) {
|
||||
return new GenericUpstreamMock(id, Chain.ETHEREUM__MAINNET, api(), Collections.singletonMap("provider", provider))
|
||||
}
|
||||
|
||||
static EthereumPosRpcUpstreamMock upstream(String id, Reader<JsonRpcRequest, JsonRpcResponse> api) {
|
||||
return new EthereumPosRpcUpstreamMock(id, Chain.ETHEREUM__MAINNET, api)
|
||||
static GenericUpstreamMock upstream(String id, Reader<JsonRpcRequest, JsonRpcResponse> api) {
|
||||
return new GenericUpstreamMock(id, Chain.ETHEREUM__MAINNET, api)
|
||||
}
|
||||
|
||||
static EthereumPosRpcUpstreamMock upstream(Reader<JsonRpcRequest, JsonRpcResponse> api) {
|
||||
return new EthereumPosRpcUpstreamMock(Chain.ETHEREUM__MAINNET, api)
|
||||
static GenericUpstreamMock upstream(Reader<JsonRpcRequest, JsonRpcResponse> api) {
|
||||
return new GenericUpstreamMock(Chain.ETHEREUM__MAINNET, api)
|
||||
}
|
||||
|
||||
static EthereumPosRpcUpstreamMock upstream(Reader<JsonRpcRequest, JsonRpcResponse> api, String method) {
|
||||
static GenericUpstreamMock upstream(Reader<JsonRpcRequest, JsonRpcResponse> api, String method) {
|
||||
return upstream(api, [method])
|
||||
}
|
||||
|
||||
static EthereumPosRpcUpstreamMock upstream(Reader<JsonRpcRequest, JsonRpcResponse> api, List<String> methods) {
|
||||
return new EthereumPosRpcUpstreamMock(Chain.ETHEREUM__MAINNET, api, new DirectCallMethods(methods))
|
||||
static GenericUpstreamMock upstream(Reader<JsonRpcRequest, JsonRpcResponse> api, List<String> methods) {
|
||||
return new GenericUpstreamMock(Chain.ETHEREUM__MAINNET, api, new DirectCallMethods(methods))
|
||||
}
|
||||
|
||||
static EthereumPosRpcUpstreamMock upstream(Reader<JsonRpcRequest, JsonRpcResponse> api, CallMethods callMethods) {
|
||||
return new EthereumPosRpcUpstreamMock(Chain.ETHEREUM__MAINNET, api, callMethods)
|
||||
static GenericUpstreamMock upstream(Reader<JsonRpcRequest, JsonRpcResponse> api, CallMethods callMethods) {
|
||||
return new GenericUpstreamMock(Chain.ETHEREUM__MAINNET, api, callMethods)
|
||||
}
|
||||
|
||||
static Multistream multistream(Reader<JsonRpcRequest, JsonRpcResponse> api) {
|
||||
return multistream(upstream(api))
|
||||
}
|
||||
|
||||
static Multistream multistream(EthereumPosRpcUpstreamMock up) {
|
||||
return new EthereumPosMultiStream(Chain.ETHEREUM__MAINNET, [up], Caches.default(), Schedulers.boundedElastic(), tracerMock()).tap {
|
||||
static Multistream multistream(GenericUpstreamMock up) {
|
||||
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()
|
||||
}
|
||||
}
|
||||
@@ -112,11 +117,17 @@ class TestingCommons {
|
||||
}
|
||||
|
||||
static Multistream multistreamWithoutUpstreams(Chain chain) {
|
||||
return new EthereumPosMultiStream(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 EthereumMultistream(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() {
|
||||
|
||||
@@ -1,253 +0,0 @@
|
||||
package io.emeraldpay.dshackle.upstream
|
||||
|
||||
import kotlin.jvm.functions.Function1
|
||||
import org.jetbrains.annotations.NotNull
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Mono
|
||||
import spock.lang.Specification
|
||||
|
||||
import java.time.Duration
|
||||
import java.util.function.Function
|
||||
|
||||
class AbstractChainFeesSpec extends Specification {
|
||||
|
||||
Function<List<String>, List<String>> extractTx = { it }
|
||||
|
||||
def "Iterates N last blocks"() {
|
||||
setup:
|
||||
def ups = Mock(Multistream) {
|
||||
1 * getHead() >> Mock(Head) {
|
||||
1 * it.getCurrentHeight() >> 234
|
||||
}
|
||||
}
|
||||
def fees = new TestChainFees(5, ups, Stub(Function1))
|
||||
when:
|
||||
def act = fees.usingBlocks(3).collectList().block(Duration.ofSeconds(1)).toSorted()
|
||||
then:
|
||||
act == [232L, 233L, 234L]
|
||||
}
|
||||
|
||||
def "Limits iteration to configured"() {
|
||||
setup:
|
||||
def ups = Mock(Multistream) {
|
||||
1 * getHead() >> Mock(Head) {
|
||||
1 * it.getCurrentHeight() >> 234
|
||||
}
|
||||
}
|
||||
def fees = new TestChainFees(3, ups, Stub(Function1))
|
||||
when:
|
||||
def act = fees.usingBlocks(5).collectList().block(Duration.ofSeconds(1)).toSorted()
|
||||
then:
|
||||
act == [232L, 233L, 234L]
|
||||
}
|
||||
|
||||
def "TxAtPos 0 for empty list"() {
|
||||
setup:
|
||||
def txAt = new AbstractChainFees.TxAtPos<List<String>, String>(extractTx, 0)
|
||||
|
||||
when:
|
||||
def act = txAt.get([])
|
||||
|
||||
then:
|
||||
act == null
|
||||
}
|
||||
|
||||
def "TxAtPos 0 for single item list"() {
|
||||
setup:
|
||||
def txAt = new AbstractChainFees.TxAtPos<List<String>, String>(extractTx, 0)
|
||||
|
||||
when:
|
||||
def act = txAt.get(["t_1"])
|
||||
|
||||
then:
|
||||
act == "t_1"
|
||||
}
|
||||
|
||||
def "TxAtPos 0 for many item list"() {
|
||||
setup:
|
||||
def txAt = new AbstractChainFees.TxAtPos<List<String>, String>(extractTx, 0)
|
||||
|
||||
when:
|
||||
def act = txAt.get(["t_1", "t_2", "t_3"])
|
||||
|
||||
then:
|
||||
act == "t_3"
|
||||
}
|
||||
|
||||
def "TxAtPos 1 for many item list"() {
|
||||
setup:
|
||||
def txAt = new AbstractChainFees.TxAtPos<List<String>, String>(extractTx, 1)
|
||||
|
||||
when:
|
||||
def act = txAt.get(["t_1", "t_2", "t_3"])
|
||||
|
||||
then:
|
||||
act == "t_2"
|
||||
}
|
||||
|
||||
def "TxAtPos 2 for many item list"() {
|
||||
setup:
|
||||
def txAt = new AbstractChainFees.TxAtPos<List<String>, String>(extractTx, 2)
|
||||
|
||||
when:
|
||||
def act = txAt.get(["t_1", "t_2", "t_3"])
|
||||
|
||||
then:
|
||||
act == "t_1"
|
||||
}
|
||||
|
||||
def "TxAtPos 5 for 3 item list"() {
|
||||
setup:
|
||||
def txAt = new AbstractChainFees.TxAtPos<List<String>, String>(extractTx, 5)
|
||||
|
||||
when:
|
||||
def act = txAt.get(["t_1", "t_2", "t_3"])
|
||||
|
||||
then:
|
||||
act == "t_1"
|
||||
}
|
||||
|
||||
def "TxAtBottom for empty list"() {
|
||||
setup:
|
||||
def txAt = new AbstractChainFees.TxAtBottom<List<String>, String>(extractTx)
|
||||
|
||||
when:
|
||||
def act = txAt.get([])
|
||||
|
||||
then:
|
||||
act == null
|
||||
}
|
||||
|
||||
def "TxAtBottom for single item list"() {
|
||||
setup:
|
||||
def txAt = new AbstractChainFees.TxAtBottom<List<String>, String>(extractTx)
|
||||
|
||||
when:
|
||||
def act = txAt.get(["t_1"])
|
||||
|
||||
then:
|
||||
act == "t_1"
|
||||
}
|
||||
|
||||
def "TxAtBottom for multi item list"() {
|
||||
setup:
|
||||
def txAt = new AbstractChainFees.TxAtBottom<List<String>, String>(extractTx)
|
||||
|
||||
when:
|
||||
def act = txAt.get(["t_1", "t_2", "t_3"])
|
||||
|
||||
then:
|
||||
act == "t_3"
|
||||
}
|
||||
|
||||
def "TxAtTop for empty list"() {
|
||||
setup:
|
||||
def txAt = new AbstractChainFees.TxAtTop<List<String>, String>(extractTx)
|
||||
|
||||
when:
|
||||
def act = txAt.get([])
|
||||
|
||||
then:
|
||||
act == null
|
||||
}
|
||||
|
||||
def "TxAtTop for single item list"() {
|
||||
setup:
|
||||
def txAt = new AbstractChainFees.TxAtTop<List<String>, String>(extractTx)
|
||||
|
||||
when:
|
||||
def act = txAt.get(["t_1"])
|
||||
|
||||
then:
|
||||
act == "t_1"
|
||||
}
|
||||
|
||||
def "TxAtTop for multi item list"() {
|
||||
setup:
|
||||
def txAt = new AbstractChainFees.TxAtTop<List<String>, String>(extractTx)
|
||||
|
||||
when:
|
||||
def act = txAt.get(["t_1", "t_2", "t_3"])
|
||||
|
||||
then:
|
||||
act == "t_1"
|
||||
}
|
||||
|
||||
def "TxAtMiddle for empty list"() {
|
||||
setup:
|
||||
def txAt = new AbstractChainFees.TxAtMiddle<List<String>, String>(extractTx)
|
||||
|
||||
when:
|
||||
def act = txAt.get([])
|
||||
|
||||
then:
|
||||
act == null
|
||||
}
|
||||
|
||||
def "TxAtMiddle for single item list"() {
|
||||
setup:
|
||||
def txAt = new AbstractChainFees.TxAtMiddle<List<String>, String>(extractTx)
|
||||
|
||||
when:
|
||||
def act = txAt.get(["t_1"])
|
||||
|
||||
then:
|
||||
act == "t_1"
|
||||
}
|
||||
|
||||
def "TxAtMiddle for 3 item list"() {
|
||||
setup:
|
||||
def txAt = new AbstractChainFees.TxAtMiddle<List<String>, String>(extractTx)
|
||||
|
||||
when:
|
||||
def act = txAt.get(["t_1", "t_2", "t_3"])
|
||||
|
||||
then:
|
||||
act == "t_2"
|
||||
}
|
||||
|
||||
def "TxAtMiddle for 4 item list"() {
|
||||
setup:
|
||||
def txAt = new AbstractChainFees.TxAtMiddle<List<String>, String>(extractTx)
|
||||
|
||||
when:
|
||||
def act = txAt.get(["t_1", "t_2", "t_3", "t_4"])
|
||||
|
||||
then:
|
||||
act == "t_2" || act == "t_3"
|
||||
}
|
||||
|
||||
def "TxAtMiddle for 5 item list"() {
|
||||
setup:
|
||||
def txAt = new AbstractChainFees.TxAtMiddle<List<String>, String>(extractTx)
|
||||
|
||||
when:
|
||||
def act = txAt.get(["t_1", "t_2", "t_3", "t_4", "t_5"])
|
||||
|
||||
then:
|
||||
act == "t_3"
|
||||
}
|
||||
|
||||
class TestChainFees extends AbstractChainFees {
|
||||
|
||||
TestChainFees(int heightLimit, @NotNull Multistream upstreams, @NotNull Function1 extractTx) {
|
||||
super(heightLimit, upstreams, extractTx)
|
||||
}
|
||||
|
||||
@Override
|
||||
Mono readFeesAt(long height, @NotNull TxAt selector) {
|
||||
return null
|
||||
}
|
||||
|
||||
@Override
|
||||
Function<Flux, Mono> feeAggregation(@NotNull Mode mode) {
|
||||
return null
|
||||
}
|
||||
|
||||
@Override
|
||||
Function getResponseBuilder() {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,8 +17,7 @@ package io.emeraldpay.dshackle.upstream
|
||||
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.startup.UpstreamChangeEvent
|
||||
import io.emeraldpay.dshackle.test.EthereumPosRpcUpstreamMock
|
||||
import io.emeraldpay.dshackle.test.EthereumRpcUpstreamMock
|
||||
import io.emeraldpay.dshackle.test.GenericUpstreamMock
|
||||
import io.emeraldpay.dshackle.test.TestingCommons
|
||||
import spock.lang.Specification
|
||||
|
||||
@@ -27,7 +26,7 @@ class CurrentMultistreamHolderSpec extends Specification {
|
||||
def "add upstream"() {
|
||||
setup:
|
||||
def current = new CurrentMultistreamHolder(TestingCommons.defaultMultistreams())
|
||||
def up = new EthereumPosRpcUpstreamMock("test", Chain.ETHEREUM__MAINNET, TestingCommons.api())
|
||||
def up = new GenericUpstreamMock("test", Chain.ETHEREUM__MAINNET, TestingCommons.api())
|
||||
when:
|
||||
current.getUpstream(Chain.ETHEREUM__MAINNET).onUpstreamChange(new UpstreamChangeEvent(Chain.ETHEREUM__MAINNET, up, UpstreamChangeEvent.ChangeType.ADDED))
|
||||
then:
|
||||
@@ -38,9 +37,9 @@ class CurrentMultistreamHolderSpec extends Specification {
|
||||
def "add multiple upstreams"() {
|
||||
setup:
|
||||
def current = new CurrentMultistreamHolder(TestingCommons.defaultMultistreams())
|
||||
def up1 = new EthereumPosRpcUpstreamMock("test1", Chain.ETHEREUM__MAINNET, TestingCommons.api())
|
||||
def up2 = new EthereumRpcUpstreamMock("test2", Chain.ETHEREUM_CLASSIC__MAINNET, TestingCommons.api())
|
||||
def up3 = new EthereumPosRpcUpstreamMock("test3", Chain.ETHEREUM__MAINNET, TestingCommons.api())
|
||||
def up1 = new GenericUpstreamMock("test1", Chain.ETHEREUM__MAINNET, TestingCommons.api())
|
||||
def up2 = new GenericUpstreamMock("test2", Chain.ETHEREUM_CLASSIC__MAINNET, TestingCommons.api())
|
||||
def up3 = new GenericUpstreamMock("test3", Chain.ETHEREUM__MAINNET, TestingCommons.api())
|
||||
when:
|
||||
current.getUpstream(Chain.ETHEREUM__MAINNET).onUpstreamChange(new UpstreamChangeEvent(Chain.ETHEREUM__MAINNET, up1, UpstreamChangeEvent.ChangeType.ADDED))
|
||||
current.getUpstream(Chain.ETHEREUM_CLASSIC__MAINNET).onUpstreamChange(new UpstreamChangeEvent(Chain.ETHEREUM_CLASSIC__MAINNET, up2, UpstreamChangeEvent.ChangeType.ADDED))
|
||||
@@ -55,10 +54,10 @@ class CurrentMultistreamHolderSpec extends Specification {
|
||||
def "remove upstream"() {
|
||||
setup:
|
||||
def current = new CurrentMultistreamHolder(TestingCommons.defaultMultistreams())
|
||||
def up1 = new EthereumPosRpcUpstreamMock("test1", Chain.ETHEREUM__MAINNET, TestingCommons.api())
|
||||
def up2 = new EthereumRpcUpstreamMock("test2", Chain.ETHEREUM_CLASSIC__MAINNET, TestingCommons.api())
|
||||
def up3 = new EthereumPosRpcUpstreamMock("test3", Chain.ETHEREUM__MAINNET, TestingCommons.api())
|
||||
def up1_del = new EthereumPosRpcUpstreamMock("test1", Chain.ETHEREUM__MAINNET, TestingCommons.api())
|
||||
def up1 = new GenericUpstreamMock("test1", Chain.ETHEREUM__MAINNET, TestingCommons.api())
|
||||
def up2 = new GenericUpstreamMock("test2", Chain.ETHEREUM_CLASSIC__MAINNET, TestingCommons.api())
|
||||
def up3 = new GenericUpstreamMock("test3", Chain.ETHEREUM__MAINNET, TestingCommons.api())
|
||||
def up1_del = new GenericUpstreamMock("test1", Chain.ETHEREUM__MAINNET, TestingCommons.api())
|
||||
when:
|
||||
current.getUpstream(Chain.ETHEREUM__MAINNET).onUpstreamChange(new UpstreamChangeEvent(Chain.ETHEREUM__MAINNET, up1, UpstreamChangeEvent.ChangeType.ADDED))
|
||||
current.getUpstream(Chain.ETHEREUM_CLASSIC__MAINNET).onUpstreamChange(new UpstreamChangeEvent(Chain.ETHEREUM_CLASSIC__MAINNET, up2, UpstreamChangeEvent.ChangeType.ADDED))
|
||||
@@ -73,7 +72,7 @@ class CurrentMultistreamHolderSpec extends Specification {
|
||||
def "available after adding"() {
|
||||
setup:
|
||||
def current = new CurrentMultistreamHolder(TestingCommons.defaultMultistreams())
|
||||
def up1 = new EthereumPosRpcUpstreamMock("test1", Chain.ETHEREUM__MAINNET, TestingCommons.api())
|
||||
def up1 = new GenericUpstreamMock("test1", Chain.ETHEREUM__MAINNET, TestingCommons.api())
|
||||
|
||||
when:
|
||||
def act = current.isAvailable(Chain.ETHEREUM__MAINNET)
|
||||
|
||||
@@ -24,7 +24,7 @@ import io.emeraldpay.dshackle.startup.QuorumForLabels
|
||||
import io.emeraldpay.dshackle.test.EthereumApiStub
|
||||
import io.emeraldpay.dshackle.test.TestingCommons
|
||||
import io.emeraldpay.dshackle.upstream.calls.DefaultEthereumMethods
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumLikeRpcUpstream
|
||||
import io.emeraldpay.dshackle.upstream.generic.GenericUpstream
|
||||
import io.emeraldpay.dshackle.upstream.generic.connectors.GenericConnectorFactory
|
||||
import io.emeraldpay.dshackle.upstream.forkchoice.MostWorkForkChoice
|
||||
import reactor.core.scheduler.Schedulers
|
||||
@@ -44,13 +44,15 @@ class FilteredApisSpec extends Specification {
|
||||
def "Verifies labels"() {
|
||||
setup:
|
||||
def i = 0
|
||||
List<EthereumLikeRpcUpstream> upstreams = [
|
||||
def cs = io.emeraldpay.dshackle.upstream.starknet.StarknetChainSpecific.INSTANCE
|
||||
List<GenericUpstream> upstreams = [
|
||||
[test: "foo"],
|
||||
[test: "bar"],
|
||||
[test: "foo", test2: "baz"],
|
||||
[test: "foo"],
|
||||
[test: "baz"]
|
||||
].collect {
|
||||
|
||||
def httpFactory = Mock(HttpFactory) {
|
||||
create(_, _) >> Stub(JsonRpcHttpReader)
|
||||
}
|
||||
@@ -64,18 +66,20 @@ class FilteredApisSpec extends Specification {
|
||||
Schedulers.boundedElastic(),
|
||||
Duration.ofSeconds(12)
|
||||
)
|
||||
new EthereumLikeRpcUpstream(
|
||||
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)),
|
||||
connectorFactory,
|
||||
ChainsConfig.ChainConfig.default(),
|
||||
false,
|
||||
null
|
||||
connectorFactory,
|
||||
null,
|
||||
cs.&validator,
|
||||
cs.&labelDetector,
|
||||
cs.&subscriptionTopics,
|
||||
)
|
||||
}
|
||||
def matcher = new Selector.LabelMatcher("test", ["foo"])
|
||||
|
||||
@@ -25,15 +25,17 @@ import io.emeraldpay.dshackle.data.BlockContainer
|
||||
import io.emeraldpay.dshackle.quorum.AlwaysQuorum
|
||||
import io.emeraldpay.dshackle.reader.Reader
|
||||
import io.emeraldpay.dshackle.startup.UpstreamChangeEvent
|
||||
import io.emeraldpay.dshackle.test.EthereumPosRpcUpstreamMock
|
||||
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.EthereumLikeRpcUpstream
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumPosMultiStream
|
||||
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
|
||||
import io.emeraldpay.dshackle.upstream.grpc.EthereumPosGrpcUpstream
|
||||
import io.emeraldpay.dshackle.upstream.grpc.GenericGrpcUpstream
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
|
||||
import io.emeraldpay.dshackle.upstream.starknet.StarknetChainSpecific
|
||||
import io.emeraldpay.etherjar.domain.BlockHash
|
||||
import io.emeraldpay.etherjar.rpc.json.TransactionRefJson
|
||||
import org.jetbrains.annotations.NotNull
|
||||
@@ -51,9 +53,13 @@ class MultistreamSpec extends Specification {
|
||||
|
||||
def "Aggregates methods"() {
|
||||
setup:
|
||||
def up1 = new EthereumPosRpcUpstreamMock("test1", Chain.ETHEREUM__MAINNET, TestingCommons.api(), new DirectCallMethods(["eth_test1", "eth_test2"]))
|
||||
def up2 = new EthereumPosRpcUpstreamMock("test1", Chain.ETHEREUM__MAINNET, TestingCommons.api(), new DirectCallMethods(["eth_test2", "eth_test3"]))
|
||||
def aggr = new EthereumPosMultiStream(Chain.ETHEREUM__MAINNET, [up1, up2], Caches.default(), Schedulers.boundedElastic(), TestingCommons.tracerMock())
|
||||
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(),
|
||||
EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(TestingCommons.tracerMock()),
|
||||
EthereumChainSpecific.INSTANCE.&localReaderBuilder,
|
||||
EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()))
|
||||
when:
|
||||
aggr.onUpstreamsUpdated()
|
||||
def act = aggr.getMethods()
|
||||
@@ -184,7 +190,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 EthereumPosMultiStream(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)
|
||||
@@ -205,14 +215,14 @@ class MultistreamSpec extends Specification {
|
||||
.setMethod("newHeads")
|
||||
.build()
|
||||
|
||||
def up1 = Mock(EthereumPosGrpcUpstream) {
|
||||
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(EthereumPosGrpcUpstream) {
|
||||
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 +245,9 @@ class MultistreamSpec extends Specification {
|
||||
.setMethod("newHeads")
|
||||
.build()
|
||||
|
||||
def up2 = Mock(EthereumPosGrpcUpstream) {
|
||||
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())
|
||||
@@ -251,9 +261,13 @@ class MultistreamSpec extends Specification {
|
||||
|
||||
def "Change ms methods based on upstream availability"() {
|
||||
setup:
|
||||
def up1 = new EthereumPosRpcUpstreamMock("test1", Chain.ETHEREUM__MAINNET, TestingCommons.api(), new DirectCallMethods(["eth_test1", "eth_test2", "eth_test3"]))
|
||||
def up2 = new EthereumPosRpcUpstreamMock("test2", Chain.ETHEREUM__MAINNET, TestingCommons.api(), new DirectCallMethods(["eth_test1", "eth_test2"]))
|
||||
def ms = new EthereumPosMultiStream(Chain.ETHEREUM__MAINNET, new ArrayList<EthereumLikeRpcUpstream>(), Caches.default(), Schedulers.boundedElastic(), TestingCommons.tracerMock())
|
||||
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<GenericMultistream>(), 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)
|
||||
@@ -278,9 +292,13 @@ class MultistreamSpec extends Specification {
|
||||
|
||||
def "Filter older blocks on multistream head"() {
|
||||
setup:
|
||||
def up1 = new EthereumPosRpcUpstreamMock("test1", Chain.ETHEREUM__MAINNET, TestingCommons.api(), new DirectCallMethods(["eth_test1", "eth_test2", "eth_test3"]))
|
||||
def up2 = new EthereumPosRpcUpstreamMock("test2", Chain.ETHEREUM__MAINNET, TestingCommons.api(), new DirectCallMethods(["eth_test1", "eth_test2"]))
|
||||
def ms = new EthereumPosMultiStream(Chain.ETHEREUM__MAINNET, new ArrayList<EthereumLikeRpcUpstream>(), Caches.default(), Schedulers.boundedElastic(), TestingCommons.tracerMock())
|
||||
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<GenericMultistream>(), 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 +329,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 EthereumPosMultiStream(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()
|
||||
|
||||
@@ -335,15 +357,19 @@ class MultistreamSpec extends Specification {
|
||||
.build()
|
||||
}
|
||||
|
||||
class TestEthereumPosMultistream extends EthereumPosMultiStream {
|
||||
class TestEthereumPosMultistream extends GenericMultistream {
|
||||
|
||||
TestEthereumPosMultistream(@NotNull Chain chain, @NotNull List<EthereumLikeRpcUpstream> upstreams, @NotNull Caches caches) {
|
||||
super(chain, upstreams, caches, Schedulers.boundedElastic(), TestingCommons.tracerMock())
|
||||
TestEthereumPosMultistream(@NotNull Chain chain, @NotNull List<GenericUpstream> upstreams, @NotNull Caches caches) {
|
||||
super(chain, upstreams, caches,
|
||||
Schedulers.boundedElastic(),
|
||||
EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(TestingCommons.tracerMock()),
|
||||
EthereumChainSpecific.INSTANCE.&localReaderBuilder,
|
||||
StarknetChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()))
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
Mono<Reader<JsonRpcRequest, JsonRpcResponse>> getLocalReader(boolean localEnabled) {
|
||||
Mono<Reader<JsonRpcRequest, JsonRpcResponse>> getLocalReader() {
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 EmeraldPay, Inc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.emeraldpay.dshackle.upstream.ethereum
|
||||
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.test.EthereumPosRpcUpstreamMock
|
||||
import io.emeraldpay.dshackle.test.ReaderMock
|
||||
import io.emeraldpay.dshackle.upstream.ApiSource
|
||||
import io.emeraldpay.dshackle.upstream.FilteredApis
|
||||
import io.emeraldpay.dshackle.upstream.Selector
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
|
||||
import io.emeraldpay.etherjar.domain.Address
|
||||
import io.emeraldpay.etherjar.erc20.ERC20Token
|
||||
import io.emeraldpay.etherjar.hex.HexData
|
||||
import io.emeraldpay.etherjar.rpc.json.TransactionCallJson
|
||||
import spock.lang.Specification
|
||||
|
||||
import java.time.Duration
|
||||
|
||||
class ERC20BalanceSpec extends Specification {
|
||||
|
||||
def "Gets balance from upstream"() {
|
||||
setup:
|
||||
ReaderMock api = new ReaderMock()
|
||||
.with(
|
||||
new JsonRpcRequest("eth_call", [
|
||||
new TransactionCallJson().tap { json ->
|
||||
json.setTo(Address.from("0x54EedeAC495271d0F6B175474E89094C44Da98b9"))
|
||||
json.setData(HexData.from("0x70a0823100000000000000000000000016c15c65ad00b6dfbcc2cb8a7b6c2d0103a3883b"))
|
||||
},
|
||||
"latest"
|
||||
]),
|
||||
JsonRpcResponse.ok('"0x0000000000000000000000000000000000000000000000000000001f28d72868"')
|
||||
)
|
||||
|
||||
EthereumLikeRpcUpstream upstream = new EthereumPosRpcUpstreamMock(Chain.ETHEREUM__MAINNET, api)
|
||||
ERC20Token token = new ERC20Token(Address.from("0x54EedeAC495271d0F6B175474E89094C44Da98b9"))
|
||||
ERC20Balance query = new ERC20Balance()
|
||||
|
||||
when:
|
||||
def act = query.getBalance(upstream, token, Address.from("0x16c15c65ad00b6dfbcc2cb8a7b6c2d0103a3883b"))
|
||||
.block(Duration.ofSeconds(1))
|
||||
|
||||
then:
|
||||
act.toLong() == 0x1f28d72868
|
||||
}
|
||||
|
||||
def "Gets balance from api source"() {
|
||||
setup:
|
||||
ReaderMock api = new ReaderMock()
|
||||
.with(
|
||||
new JsonRpcRequest("eth_call", [
|
||||
new TransactionCallJson().tap { json ->
|
||||
json.setTo(Address.from("0x54EedeAC495271d0F6B175474E89094C44Da98b9"))
|
||||
json.setData(HexData.from("0x70a0823100000000000000000000000016c15c65ad00b6dfbcc2cb8a7b6c2d0103a3883b"))
|
||||
},
|
||||
"latest"
|
||||
]),
|
||||
JsonRpcResponse.ok('"0x0000000000000000000000000000000000000000000000000000001f28d72868"')
|
||||
)
|
||||
|
||||
EthereumLikeRpcUpstream upstream = new EthereumPosRpcUpstreamMock(Chain.ETHEREUM__MAINNET, api)
|
||||
ERC20Token token = new ERC20Token(Address.from("0x54EedeAC495271d0F6B175474E89094C44Da98b9"))
|
||||
ERC20Balance query = new ERC20Balance()
|
||||
|
||||
ApiSource apiSource = new FilteredApis(
|
||||
Chain.ETHEREUM__MAINNET, [upstream], Selector.empty
|
||||
)
|
||||
|
||||
when:
|
||||
def act = query.getBalance(apiSource, token, Address.from("0x16c15c65ad00b6dfbcc2cb8a7b6c2d0103a3883b"))
|
||||
.block(Duration.ofSeconds(1))
|
||||
|
||||
then:
|
||||
act.toLong() == 0x1f28d72868
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ package io.emeraldpay.dshackle.upstream.ethereum
|
||||
|
||||
|
||||
import io.emeraldpay.dshackle.test.TestingCommons
|
||||
import io.emeraldpay.dshackle.upstream.generic.GenericMultistream
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.subscribe.PendingTxesSource
|
||||
import io.emeraldpay.etherjar.domain.Address
|
||||
import io.emeraldpay.etherjar.hex.Hex32
|
||||
@@ -28,7 +29,7 @@ class EthereumEgressSubscriptionSpec extends Specification {
|
||||
|
||||
def "read empty logs request"() {
|
||||
setup:
|
||||
def ethereumSubscribe = new EthereumEgressSubscription(TestingCommons.emptyMultistream() as EthereumPosMultiStream, Schedulers.boundedElastic(), Stub(PendingTxesSource))
|
||||
def ethereumSubscribe = new EthereumEgressSubscription(TestingCommons.emptyMultistream() as GenericMultistream, Schedulers.boundedElastic(), Stub(PendingTxesSource))
|
||||
when:
|
||||
def act = ethereumSubscribe.readLogsRequest([:])
|
||||
|
||||
@@ -39,7 +40,7 @@ class EthereumEgressSubscriptionSpec extends Specification {
|
||||
|
||||
def "read single address logs request"() {
|
||||
setup:
|
||||
def ethereumSubscribe = new EthereumEgressSubscription(TestingCommons.emptyMultistream() as EthereumPosMultiStream, Schedulers.boundedElastic(), Stub(PendingTxesSource))
|
||||
def ethereumSubscribe = new EthereumEgressSubscription(TestingCommons.emptyMultistream() as GenericMultistream, Schedulers.boundedElastic(), Stub(PendingTxesSource))
|
||||
when:
|
||||
def act = ethereumSubscribe.readLogsRequest([
|
||||
address: "0x829bd824b016326a401d083b33d092293333a830"
|
||||
@@ -64,7 +65,7 @@ class EthereumEgressSubscriptionSpec extends Specification {
|
||||
|
||||
def "ignores invalid address for logs request"() {
|
||||
setup:
|
||||
def ethereumSubscribe = new EthereumEgressSubscription(TestingCommons.emptyMultistream() as EthereumPosMultiStream, Schedulers.boundedElastic(), Stub(PendingTxesSource))
|
||||
def ethereumSubscribe = new EthereumEgressSubscription(TestingCommons.emptyMultistream() as GenericMultistream, Schedulers.boundedElastic(), Stub(PendingTxesSource))
|
||||
when:
|
||||
def act = ethereumSubscribe.readLogsRequest([
|
||||
address: "829bd824b016326a401d083b33d092293333a830"
|
||||
@@ -77,7 +78,7 @@ class EthereumEgressSubscriptionSpec extends Specification {
|
||||
|
||||
def "read multi address logs request"() {
|
||||
setup:
|
||||
def ethereumSubscribe = new EthereumEgressSubscription(TestingCommons.emptyMultistream() as EthereumPosMultiStream, Schedulers.boundedElastic(), Stub(PendingTxesSource))
|
||||
def ethereumSubscribe = new EthereumEgressSubscription(TestingCommons.emptyMultistream() as GenericMultistream, Schedulers.boundedElastic(), Stub(PendingTxesSource))
|
||||
when:
|
||||
def act = ethereumSubscribe.readLogsRequest([
|
||||
address: ["0x829bd824b016326a401d083b33d092293333a830", "0x401d083b33d092293333a83829bd824b016326a0"]
|
||||
@@ -93,7 +94,7 @@ class EthereumEgressSubscriptionSpec extends Specification {
|
||||
|
||||
def "read single topic logs request"() {
|
||||
setup:
|
||||
def ethereumSubscribe = new EthereumEgressSubscription(TestingCommons.emptyMultistream() as EthereumPosMultiStream, Schedulers.boundedElastic(), Stub(PendingTxesSource))
|
||||
def ethereumSubscribe = new EthereumEgressSubscription(TestingCommons.emptyMultistream() as GenericMultistream, Schedulers.boundedElastic(), Stub(PendingTxesSource))
|
||||
when:
|
||||
def act = ethereumSubscribe.readLogsRequest([
|
||||
topics: "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
|
||||
@@ -118,7 +119,7 @@ class EthereumEgressSubscriptionSpec extends Specification {
|
||||
|
||||
def "read invalid topic for request"() {
|
||||
setup:
|
||||
def ethereumSubscribe = new EthereumEgressSubscription(TestingCommons.emptyMultistream() as EthereumPosMultiStream, Schedulers.boundedElastic(), Stub(PendingTxesSource))
|
||||
def ethereumSubscribe = new EthereumEgressSubscription(TestingCommons.emptyMultistream() as GenericMultistream, Schedulers.boundedElastic(), Stub(PendingTxesSource))
|
||||
when:
|
||||
def act = ethereumSubscribe.readLogsRequest([
|
||||
topics: [
|
||||
@@ -136,7 +137,7 @@ class EthereumEgressSubscriptionSpec extends Specification {
|
||||
|
||||
def "read multi topic logs request"() {
|
||||
setup:
|
||||
def ethereumSubscribe = new EthereumEgressSubscription(TestingCommons.emptyMultistream() as EthereumPosMultiStream, Schedulers.boundedElastic(), Stub(PendingTxesSource))
|
||||
def ethereumSubscribe = new EthereumEgressSubscription(TestingCommons.emptyMultistream() as GenericMultistream, Schedulers.boundedElastic(), Stub(PendingTxesSource))
|
||||
when:
|
||||
def act = ethereumSubscribe.readLogsRequest([
|
||||
topics: [
|
||||
@@ -155,7 +156,7 @@ class EthereumEgressSubscriptionSpec extends Specification {
|
||||
|
||||
def "read full logs request"() {
|
||||
setup:
|
||||
def ethereumSubscribe = new EthereumEgressSubscription(TestingCommons.emptyMultistream() as EthereumPosMultiStream, Schedulers.boundedElastic(), Stub(PendingTxesSource))
|
||||
def ethereumSubscribe = new EthereumEgressSubscription(TestingCommons.emptyMultistream() as GenericMultistream, Schedulers.boundedElastic(), Stub(PendingTxesSource))
|
||||
when:
|
||||
def act = ethereumSubscribe.readLogsRequest([
|
||||
address: "0x298d492e8c1d909d3f63bc4a36c66c64acb3d695",
|
||||
@@ -180,7 +181,7 @@ class EthereumEgressSubscriptionSpec extends Specification {
|
||||
def up1 = TestingCommons.upstream("test")
|
||||
up1.getConnectorMock().setLiveness(Flux.just(false))
|
||||
|
||||
def ethereumSubscribe1 = new EthereumEgressSubscription(TestingCommons.multistream(up1) as EthereumPosMultiStream, Schedulers.boundedElastic(), null)
|
||||
def ethereumSubscribe1 = new EthereumEgressSubscription(TestingCommons.multistream(up1) as GenericMultistream, Schedulers.boundedElastic(), null)
|
||||
then:
|
||||
ethereumSubscribe1.getAvailableTopics() == []
|
||||
when:
|
||||
@@ -188,7 +189,7 @@ class EthereumEgressSubscriptionSpec extends Specification {
|
||||
up2.getConnectorMock().setLiveness(Flux.just(true))
|
||||
up2.stop()
|
||||
up2.start()
|
||||
def ethereumSubscribe2 = new EthereumEgressSubscription(TestingCommons.multistream(up2) as EthereumPosMultiStream, Schedulers.boundedElastic(), null)
|
||||
def ethereumSubscribe2 = new EthereumEgressSubscription(TestingCommons.multistream(up2) as GenericMultistream, Schedulers.boundedElastic(), null)
|
||||
then:
|
||||
ethereumSubscribe2.getAvailableTopics().toSet() == [EthereumEgressSubscription.METHOD_LOGS, EthereumEgressSubscription.METHOD_NEW_HEADS].toSet()
|
||||
when:
|
||||
@@ -196,7 +197,7 @@ class EthereumEgressSubscriptionSpec extends Specification {
|
||||
up3.getConnectorMock().setLiveness(Flux.just(true))
|
||||
up3.stop()
|
||||
up3.start()
|
||||
def ethereumSubscribe3 = new EthereumEgressSubscription(TestingCommons.multistream(up3) as EthereumPosMultiStream, Schedulers.boundedElastic(), Stub(PendingTxesSource))
|
||||
def ethereumSubscribe3 = new EthereumEgressSubscription(TestingCommons.multistream(up3) as GenericMultistream, Schedulers.boundedElastic(), Stub(PendingTxesSource))
|
||||
then:
|
||||
ethereumSubscribe3.getAvailableTopics().toSet() == [EthereumEgressSubscription.METHOD_LOGS, EthereumEgressSubscription.METHOD_NEW_HEADS, EthereumEgressSubscription.METHOD_PENDING_TXES].toSet()
|
||||
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 EmeraldPay, Inc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.emeraldpay.dshackle.upstream.ethereum
|
||||
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.json.BlockJson
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.json.TransactionJsonSnapshot
|
||||
import io.emeraldpay.etherjar.domain.Wei
|
||||
import spock.lang.Specification
|
||||
|
||||
class EthereumLegacyFeesSpec extends Specification {
|
||||
|
||||
def "Extract fee from"() {
|
||||
setup:
|
||||
def block = new BlockJson()
|
||||
// 0x75cc01873a9818bf426a8b23d83450bf18530a822fd4fe9e86a416a5554176a6
|
||||
def tx = new TransactionJsonSnapshot().tap {
|
||||
it.gasPrice = Wei.ofUnits(8, Wei.Unit.GWEI)
|
||||
}
|
||||
|
||||
def fees = new EthereumLegacyFees(Stub(EthereumMultistream), Stub(EthereumCachingReader), 10)
|
||||
when:
|
||||
def act = fees.extractFee(block, tx)
|
||||
then:
|
||||
act.priority == Wei.ofUnits(8, Wei.Unit.GWEI)
|
||||
act.max == Wei.ofUnits(8, Wei.Unit.GWEI)
|
||||
act.base == Wei.ZERO
|
||||
}
|
||||
}
|
||||
@@ -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])
|
||||
|
||||
@@ -1,150 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 EmeraldPay, Inc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.emeraldpay.dshackle.upstream.ethereum
|
||||
|
||||
import io.emeraldpay.dshackle.reader.Reader
|
||||
import io.emeraldpay.dshackle.upstream.ChainFees
|
||||
import io.emeraldpay.dshackle.upstream.Head
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.json.BlockJson
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.json.TransactionJsonSnapshot
|
||||
import io.emeraldpay.etherjar.domain.TransactionId
|
||||
import io.emeraldpay.etherjar.domain.Wei
|
||||
import io.emeraldpay.etherjar.rpc.json.TransactionRefJson
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Mono
|
||||
import spock.lang.Specification
|
||||
|
||||
import java.time.Duration
|
||||
|
||||
class EthereumPriorityFeesSpec extends Specification {
|
||||
|
||||
def "Extract fee from EIP1559 tx"() {
|
||||
setup:
|
||||
// 13756007
|
||||
def block = new BlockJson().tap {
|
||||
it.baseFeePerGas = new Wei(104197355513)
|
||||
}
|
||||
// 0x5da50f35a51e56ecd4313417b1c30f9c088222f3f8763701effe14f3dd18b6cc
|
||||
def tx = new TransactionJsonSnapshot().tap {
|
||||
it.type = 2
|
||||
it.maxFeePerGas = Wei.ofUnits(999, Wei.Unit.GWEI)
|
||||
it.maxPriorityFeePerGas = Wei.ofUnits(5.0001, Wei.Unit.GWEI)
|
||||
}
|
||||
|
||||
def fees = new EthereumPriorityFees(Stub(EthereumMultistream), Stub(EthereumCachingReader), 10)
|
||||
when:
|
||||
def act = fees.extractFee(block, tx)
|
||||
then:
|
||||
act.priority == Wei.ofUnits(5.0001, Wei.Unit.GWEI)
|
||||
act.max == Wei.ofUnits(999, Wei.Unit.GWEI)
|
||||
act.base == new Wei(104197355513)
|
||||
}
|
||||
|
||||
def "Extract fee from legacy tx"() {
|
||||
setup:
|
||||
// 13756007
|
||||
def block = new BlockJson().tap {
|
||||
it.baseFeePerGas = new Wei(104197355513)
|
||||
}
|
||||
// 0x1f507982bef0f11a8304287d41f228b5f1dda1114a446ee781c3d95ef4a7b891
|
||||
def tx = new TransactionJsonSnapshot().tap {
|
||||
it.type = 0
|
||||
// 109.564020111 Gwei
|
||||
it.gasPrice = Wei.from("0x198286458f")
|
||||
}
|
||||
|
||||
def fees = new EthereumPriorityFees(Stub(EthereumMultistream), Stub(EthereumCachingReader), 10)
|
||||
when:
|
||||
def act = fees.extractFee(block, tx)
|
||||
then:
|
||||
// as difference between base minimum and actually paid
|
||||
act.priority == Wei.ofUnits(5.366664598, Wei.Unit.GWEI)
|
||||
act.max == Wei.from("0x198286458f")
|
||||
act.base == new Wei(104197355513)
|
||||
}
|
||||
|
||||
def "Calculates average fee"() {
|
||||
setup:
|
||||
def inputs = [
|
||||
new EthereumFees.EthereumFee(Wei.ofEthers(1), Wei.ofEthers(0.5), Wei.ofEthers(0.75), Wei.ofEthers(0.5)),
|
||||
new EthereumFees.EthereumFee(Wei.ofEthers(0.75), Wei.ofEthers(0.5), Wei.ofEthers(0.75), Wei.ofEthers(0.5)),
|
||||
new EthereumFees.EthereumFee(Wei.ofEthers(0.6), Wei.ofEthers(0.2), Wei.ofEthers(0.6), Wei.ofEthers(0.5)),
|
||||
]
|
||||
def fees = new EthereumPriorityFees(Stub(EthereumMultistream), Stub(EthereumCachingReader), 10)
|
||||
when:
|
||||
def act = Flux.fromIterable(inputs)
|
||||
.transform(fees.feeAggregation(ChainFees.Mode.AVG_LAST))
|
||||
.next().block(Duration.ofSeconds(1))
|
||||
then:
|
||||
act.priority == Wei.ofEthers(0.4) // 0.5 + 0.5 + 0.2
|
||||
act.paid == Wei.ofEthers(0.7) // 0.75 + 0.75 + 0.6
|
||||
}
|
||||
|
||||
def "Estimate"() {
|
||||
setup:
|
||||
def block1 = new BlockJson().tap {
|
||||
it.baseFeePerGas = new Wei(92633661632)
|
||||
it.transactions = [
|
||||
new TransactionRefJson(TransactionId.from("0x00000000fad596cad644b785a8a74f6580ceec9ae13c8aa174f819c0223b8c77")),
|
||||
new TransactionRefJson(TransactionId.from("0x11111111fad596cad644b785a8a74f6580ceec9ae13c8aa174f819c0223b8c77")),
|
||||
new TransactionRefJson(TransactionId.from("0x22222222fad596cad644b785a8a74f6580ceec9ae13c8aa174f819c0223b8c77")),
|
||||
]
|
||||
}
|
||||
def block2 = new BlockJson().tap {
|
||||
it.baseFeePerGas = new Wei(104197355513)
|
||||
it.transactions = [
|
||||
new TransactionRefJson(TransactionId.from("0x33333333fad596cad644b785a8a74f6580ceec9ae13c8aa174f819c0223b8c77")),
|
||||
new TransactionRefJson(TransactionId.from("0x44444444fad596cad644b785a8a74f6580ceec9ae13c8aa174f819c0223b8c77")),
|
||||
new TransactionRefJson(TransactionId.from("0x55555555fad596cad644b785a8a74f6580ceec9ae13c8aa174f819c0223b8c77")),
|
||||
]
|
||||
}
|
||||
def tx1 = new TransactionJsonSnapshot().tap {
|
||||
it.type = 2
|
||||
it.maxFeePerGas = Wei.ofUnits(150, Wei.Unit.GWEI)
|
||||
it.maxPriorityFeePerGas = Wei.ofUnits(3, Wei.Unit.GWEI)
|
||||
}
|
||||
def tx2 = new TransactionJsonSnapshot().tap {
|
||||
it.type = 2
|
||||
it.maxFeePerGas = Wei.ofUnits(200, Wei.Unit.GWEI)
|
||||
it.maxPriorityFeePerGas = Wei.ofUnits(6, Wei.Unit.GWEI)
|
||||
}
|
||||
|
||||
def ups = Mock(EthereumMultistream) {
|
||||
1 * getHead() >> Mock(Head) {
|
||||
1 * getCurrentHeight() >> 13756007
|
||||
}
|
||||
}
|
||||
def reader = Mock(EthereumCachingReader) {
|
||||
_ * it.blocksByHeightParsed() >> Mock(Reader) {
|
||||
1 * it.read(13756006) >> Mono.just(block1)
|
||||
1 * it.read(13756007) >> Mono.just(block2)
|
||||
}
|
||||
_ * it.txByHash() >> Mock(Reader) {
|
||||
1 * it.read(TransactionId.from("0x22222222fad596cad644b785a8a74f6580ceec9ae13c8aa174f819c0223b8c77")) >> Mono.just(tx1)
|
||||
1 * it.read(TransactionId.from("0x55555555fad596cad644b785a8a74f6580ceec9ae13c8aa174f819c0223b8c77")) >> Mono.just(tx2)
|
||||
}
|
||||
}
|
||||
def fees = new EthereumPriorityFees(ups, reader, 10)
|
||||
when:
|
||||
def act = fees.estimate(ChainFees.Mode.AVG_LAST, 2).block(Duration.ofSeconds(1))
|
||||
|
||||
then:
|
||||
act.hasEthereumExtended()
|
||||
act.ethereumExtended.priority == "4500000000"
|
||||
act.ethereumExtended.max == "175000000000"
|
||||
act.ethereumExtended.expect == "102915508572"
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -37,16 +38,20 @@ import java.time.Duration
|
||||
import static io.emeraldpay.dshackle.Chain.ETHEREUM__MAINNET
|
||||
import static io.emeraldpay.dshackle.Chain.OPTIMISM__MAINNET
|
||||
import static io.emeraldpay.dshackle.upstream.UpstreamAvailability.*
|
||||
import static io.emeraldpay.dshackle.upstream.ethereum.EthereumUpstreamValidator.ValidateUpstreamSettingsResult.UPSTREAM_FATAL_SETTINGS_ERROR
|
||||
import static io.emeraldpay.dshackle.upstream.ethereum.EthereumUpstreamValidator.ValidateUpstreamSettingsResult.UPSTREAM_SETTINGS_ERROR
|
||||
import static io.emeraldpay.dshackle.upstream.ethereum.EthereumUpstreamValidator.ValidateUpstreamSettingsResult.UPSTREAM_VALID
|
||||
import static io.emeraldpay.dshackle.upstream.ValidateUpstreamSettingsResult.UPSTREAM_FATAL_SETTINGS_ERROR
|
||||
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:
|
||||
|
||||
@@ -18,7 +18,7 @@ package io.emeraldpay.dshackle.upstream.ethereum
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.Global
|
||||
import io.emeraldpay.dshackle.data.BlockContainer
|
||||
import io.emeraldpay.dshackle.test.EthereumPosRpcUpstreamMock
|
||||
import io.emeraldpay.dshackle.test.GenericUpstreamMock
|
||||
import io.emeraldpay.dshackle.test.TestingCommons
|
||||
import io.emeraldpay.dshackle.upstream.BlockValidator
|
||||
import io.emeraldpay.dshackle.upstream.DefaultUpstream
|
||||
@@ -41,7 +41,7 @@ import java.time.temporal.ChronoUnit
|
||||
class EthereumWsHeadSpec extends Specification {
|
||||
|
||||
BlockHash parent = BlockHash.from("0x3ec2ebf5d0ec474d0ac6bc50d2770d8409ad76e119968e7919f85d5ec8915200")
|
||||
DefaultUpstream upstream = new EthereumPosRpcUpstreamMock(Chain.ETHEREUM__MAINNET, TestingCommons.api())
|
||||
DefaultUpstream upstream = new GenericUpstreamMock(Chain.ETHEREUM__MAINNET, TestingCommons.api())
|
||||
|
||||
def "Fetch block"() {
|
||||
setup:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package io.emeraldpay.dshackle.upstream.ethereum
|
||||
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.test.EthereumPosRpcUpstreamMock
|
||||
import io.emeraldpay.dshackle.test.GenericUpstreamMock
|
||||
import io.emeraldpay.dshackle.test.MockWSServer
|
||||
import io.emeraldpay.dshackle.test.TestingCommons
|
||||
import io.emeraldpay.dshackle.upstream.DefaultUpstream
|
||||
@@ -15,7 +15,7 @@ import spock.lang.Specification
|
||||
import java.time.Duration
|
||||
|
||||
class WsConnectionImplRealSpec extends Specification {
|
||||
DefaultUpstream upstream = new EthereumPosRpcUpstreamMock(Chain.ETHEREUM__MAINNET, TestingCommons.api())
|
||||
DefaultUpstream upstream = new GenericUpstreamMock(Chain.ETHEREUM__MAINNET, TestingCommons.api())
|
||||
|
||||
static SLEEP = 500
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ package io.emeraldpay.dshackle.upstream.ethereum
|
||||
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.Global
|
||||
import io.emeraldpay.dshackle.test.EthereumPosRpcUpstreamMock
|
||||
import io.emeraldpay.dshackle.test.GenericUpstreamMock
|
||||
import io.emeraldpay.dshackle.test.TestingCommons
|
||||
import io.emeraldpay.dshackle.upstream.DefaultUpstream
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
||||
@@ -32,7 +32,7 @@ import spock.lang.Specification
|
||||
import java.time.Duration
|
||||
|
||||
class WsConnectionImplSpec extends Specification {
|
||||
DefaultUpstream upstream = new EthereumPosRpcUpstreamMock(Chain.ETHEREUM__MAINNET, TestingCommons.api())
|
||||
DefaultUpstream upstream = new GenericUpstreamMock(Chain.ETHEREUM__MAINNET, TestingCommons.api())
|
||||
|
||||
def "Makes a RPC call"() {
|
||||
setup:
|
||||
|
||||
@@ -20,7 +20,7 @@ import io.emeraldpay.dshackle.data.BlockId
|
||||
import io.emeraldpay.dshackle.data.TxId
|
||||
import io.emeraldpay.dshackle.upstream.Head
|
||||
import io.emeraldpay.dshackle.upstream.Selector
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumMultistream
|
||||
import io.emeraldpay.dshackle.upstream.generic.GenericMultistream
|
||||
import io.emeraldpay.etherjar.domain.BlockHash
|
||||
import io.emeraldpay.etherjar.domain.TransactionId
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.json.BlockJson
|
||||
@@ -38,7 +38,7 @@ class ConnectBlockUpdatesSpec extends Specification {
|
||||
|
||||
def "Extracts updates"() {
|
||||
setup:
|
||||
def connectBlockUpdates = new ConnectBlockUpdates(Stub(EthereumMultistream), Schedulers.boundedElastic())
|
||||
def connectBlockUpdates = new ConnectBlockUpdates(Stub(GenericMultistream), Schedulers.boundedElastic())
|
||||
def block = BlockContainer.from(new BlockJson<TransactionRefJson>().tap {
|
||||
hash = BlockHash.from("0xe5be2159b2b7daf6b126babdcbaa349da668b92d6b8c7db1350fd527fec4885c")
|
||||
number = 13412871
|
||||
@@ -72,7 +72,7 @@ class ConnectBlockUpdatesSpec extends Specification {
|
||||
|
||||
def "Produce DROP updates for replaced block"() {
|
||||
setup:
|
||||
def connectBlockUpdates = new ConnectBlockUpdates(Stub(EthereumMultistream), Schedulers.boundedElastic())
|
||||
def connectBlockUpdates = new ConnectBlockUpdates(Stub(GenericMultistream), Schedulers.boundedElastic())
|
||||
def block = BlockContainer.from(new BlockJson<TransactionRefJson>().tap {
|
||||
hash = BlockHash.from("0xe5be2159b2b7daf6b126babdcbaa349da668b92d6b8c7db1350fd527fec4885c")
|
||||
number = 13412871
|
||||
@@ -106,7 +106,7 @@ class ConnectBlockUpdatesSpec extends Specification {
|
||||
|
||||
def "Gets prev version if available"() {
|
||||
setup:
|
||||
def connectBlockUpdates = new ConnectBlockUpdates(Stub(EthereumMultistream), Schedulers.boundedElastic())
|
||||
def connectBlockUpdates = new ConnectBlockUpdates(Stub(GenericMultistream), Schedulers.boundedElastic())
|
||||
def block1 = BlockContainer.from(new BlockJson<TransactionRefJson>().tap {
|
||||
hash = BlockHash.from("0xe5be2159b2b7daf6b126babdcbaa349da668b92d6b8c7db1350fd527fec4885c")
|
||||
number = 13412871
|
||||
@@ -170,7 +170,7 @@ class ConnectBlockUpdatesSpec extends Specification {
|
||||
|
||||
def "Marks old txes as dropped before producing a new version of same block"() {
|
||||
setup:
|
||||
def connectBlockUpdates = new ConnectBlockUpdates(Stub(EthereumMultistream), Schedulers.boundedElastic())
|
||||
def connectBlockUpdates = new ConnectBlockUpdates(Stub(GenericMultistream), Schedulers.boundedElastic())
|
||||
def block1 = BlockContainer.from(new BlockJson<TransactionRefJson>().tap {
|
||||
hash = BlockHash.from("0xe5be2159b2b7daf6b126babdcbaa349da668b92d6b8c7db1350fd527fec4885c")
|
||||
number = 13412871
|
||||
@@ -232,7 +232,7 @@ class ConnectBlockUpdatesSpec extends Specification {
|
||||
def head = Mock(Head) {
|
||||
1 * getFlux() >> Flux.never()
|
||||
}
|
||||
def up = Mock(EthereumMultistream) {
|
||||
def up = Mock(GenericMultistream) {
|
||||
1 * getEnrichedHead(Selector.empty) >> head
|
||||
}
|
||||
def connectBlockUpdates = new ConnectBlockUpdates(up, Schedulers.boundedElastic())
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
package io.emeraldpay.dshackle.upstream.ethereum.subscribe
|
||||
|
||||
import io.emeraldpay.dshackle.test.TestingCommons
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumPosMultiStream
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.subscribe.json.LogMessage
|
||||
import io.emeraldpay.etherjar.domain.Address
|
||||
import io.emeraldpay.etherjar.domain.BlockHash
|
||||
@@ -91,7 +90,7 @@ class ConnectLogsSpec extends Specification {
|
||||
|
||||
def "Filter is empty"() {
|
||||
setup:
|
||||
def connectLogs = new ConnectLogs(TestingCommons.emptyMultistream() as EthereumPosMultiStream, Schedulers.boundedElastic())
|
||||
def connectLogs = new ConnectLogs(TestingCommons.emptyMultistream(), Schedulers.boundedElastic())
|
||||
when:
|
||||
def input = Flux.fromIterable([
|
||||
log1, log2, log3, log4
|
||||
@@ -109,7 +108,7 @@ class ConnectLogsSpec extends Specification {
|
||||
|
||||
def "Filter by address"() {
|
||||
setup:
|
||||
def connectLogs = new ConnectLogs(TestingCommons.emptyMultistream() as EthereumPosMultiStream, Schedulers.boundedElastic())
|
||||
def connectLogs = new ConnectLogs(TestingCommons.emptyMultistream(), Schedulers.boundedElastic())
|
||||
when:
|
||||
def input = Flux.fromIterable([
|
||||
log1, log2
|
||||
@@ -124,7 +123,7 @@ class ConnectLogsSpec extends Specification {
|
||||
|
||||
def "Filter by topic"() {
|
||||
setup:
|
||||
def connectLogs = new ConnectLogs(TestingCommons.emptyMultistream() as EthereumPosMultiStream, Schedulers.boundedElastic())
|
||||
def connectLogs = new ConnectLogs(TestingCommons.emptyMultistream(), Schedulers.boundedElastic())
|
||||
when:
|
||||
def input = Flux.fromIterable([
|
||||
log1, log2, log3, log4
|
||||
@@ -141,7 +140,7 @@ class ConnectLogsSpec extends Specification {
|
||||
|
||||
def "Filter by address and topic"() {
|
||||
setup:
|
||||
def connectLogs = new ConnectLogs(TestingCommons.emptyMultistream() as EthereumPosMultiStream, Schedulers.boundedElastic())
|
||||
def connectLogs = new ConnectLogs(TestingCommons.emptyMultistream(), Schedulers.boundedElastic())
|
||||
when:
|
||||
def input = Flux.fromIterable([
|
||||
log1, log2, log3, log4
|
||||
|
||||
@@ -3,7 +3,7 @@ package io.emeraldpay.dshackle.upstream.ethereum.subscribe
|
||||
import io.emeraldpay.dshackle.test.TestingCommons
|
||||
import io.emeraldpay.dshackle.upstream.Head
|
||||
import io.emeraldpay.dshackle.upstream.Selector
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumMultistream
|
||||
import io.emeraldpay.dshackle.upstream.generic.GenericMultistream
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.scheduler.Schedulers
|
||||
import reactor.test.StepVerifier
|
||||
@@ -18,7 +18,7 @@ class ConnectNewHeadsSpec extends Specification {
|
||||
TestingCommons.blockForEthereum(100)
|
||||
])
|
||||
}
|
||||
def up = Mock(EthereumMultistream) {
|
||||
def up = Mock(GenericMultistream) {
|
||||
1 * getHead(Selector.empty) >> head
|
||||
}
|
||||
ConnectNewHeads connectNewHeads = new ConnectNewHeads(up, Schedulers.boundedElastic())
|
||||
|
||||
@@ -1,264 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2019 ETCDEV GmbH
|
||||
* Copyright (c) 2020 EmeraldPay, Inc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.emeraldpay.dshackle.upstream.grpc
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.google.protobuf.ByteString
|
||||
import io.emeraldpay.api.proto.BlockchainGrpc
|
||||
import io.emeraldpay.api.proto.BlockchainOuterClass
|
||||
import io.emeraldpay.api.proto.Common
|
||||
import io.emeraldpay.dshackle.Chain
|
||||
import io.emeraldpay.dshackle.Global
|
||||
import io.emeraldpay.dshackle.config.ChainsConfig
|
||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||
import io.emeraldpay.dshackle.data.BlockId
|
||||
import io.emeraldpay.dshackle.test.MockGrpcServer
|
||||
import io.emeraldpay.dshackle.test.TestingCommons
|
||||
import io.emeraldpay.dshackle.upstream.BuildInfo
|
||||
import io.emeraldpay.dshackle.upstream.UpstreamAvailability
|
||||
import io.emeraldpay.dshackle.upstream.ethereum.json.BlockJson
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcGrpcClient
|
||||
import io.emeraldpay.dshackle.upstream.rpcclient.RpcMetrics
|
||||
import io.emeraldpay.etherjar.domain.BlockHash
|
||||
import io.grpc.stub.StreamObserver
|
||||
import io.micrometer.core.instrument.Counter
|
||||
import io.micrometer.core.instrument.Timer
|
||||
import reactor.core.scheduler.Schedulers
|
||||
import spock.lang.Specification
|
||||
|
||||
import java.time.Duration
|
||||
import java.time.Instant
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
class EthereumGrpcUpstreamSpec extends Specification {
|
||||
|
||||
MockGrpcServer mockServer = new MockGrpcServer()
|
||||
ObjectMapper objectMapper = Global.objectMapper
|
||||
RpcMetrics metrics = new RpcMetrics(
|
||||
Timer.builder("test1").register(TestingCommons.meterRegistry),
|
||||
Counter.builder("test2").register(TestingCommons.meterRegistry)
|
||||
)
|
||||
BlockHash parent = BlockHash.from("0x50d26e119968e791970d84a7bf5d0ec474d3ec2ef85d5ec8915210ac6bc09ad7")
|
||||
|
||||
def hash = (byte)123
|
||||
def buildInfo = new BuildInfo("v0.0.1-test")
|
||||
|
||||
def "Subscribe to head"() {
|
||||
setup:
|
||||
def callData = [:]
|
||||
def chain = Chain.ETHEREUM__MAINNET
|
||||
def api = TestingCommons.api()
|
||||
def block1 = new BlockJson().with {
|
||||
it.number = 650246
|
||||
it.hash = BlockHash.from("0x50d26e119968e791970d84a7bf5d0ec474d3ec2ef85d5ec8915210ac6bc09ad7")
|
||||
it.totalDifficulty = new BigInteger("35bbde5595de6456", 16)
|
||||
it.timestamp = Instant.now()
|
||||
it.parentHash = parent
|
||||
return it
|
||||
}
|
||||
api.answer("eth_getBlockByHash", [block1.hash.toHex(), false], block1)
|
||||
def client = mockServer.clientForServer(new BlockchainGrpc.BlockchainImplBase() {
|
||||
@Override
|
||||
void nativeCall(BlockchainOuterClass.NativeCallRequest request, StreamObserver<BlockchainOuterClass.NativeCallReplyItem> responseObserver) {
|
||||
api.nativeCall(request, responseObserver)
|
||||
}
|
||||
|
||||
@Override
|
||||
void subscribeHead(Common.Chain request, StreamObserver<BlockchainOuterClass.ChainHead> responseObserver) {
|
||||
callData.chain = request.getTypeValue()
|
||||
responseObserver.onNext(
|
||||
BlockchainOuterClass.ChainHead.newBuilder()
|
||||
.setBlockId(block1.hash.toHex().substring(2))
|
||||
.setHeight(block1.number)
|
||||
.setParentBlockId(parent.toHex().substring(2))
|
||||
.setWeight(ByteString.copyFrom(block1.totalDifficulty.toByteArray()))
|
||||
.build()
|
||||
)
|
||||
}
|
||||
})
|
||||
def upstream = new EthereumGrpcUpstream("test", hash, UpstreamsConfig.UpstreamRole.PRIMARY, chain, client, new JsonRpcGrpcClient(client, chain, metrics), null, ChainsConfig.ChainConfig.default(), Schedulers.boundedElastic())
|
||||
upstream.setLag(0)
|
||||
upstream.update(
|
||||
BlockchainOuterClass.DescribeChain.newBuilder()
|
||||
.setStatus(BlockchainOuterClass.ChainStatus.newBuilder().setQuorum(1).setAvailabilityValue(UpstreamAvailability.OK.grpcId))
|
||||
.addAllSupportedMethods(["eth_getBlockByHash"])
|
||||
.build(),
|
||||
BlockchainOuterClass.BuildInfo.newBuilder()
|
||||
.setVersion(buildInfo.version)
|
||||
.build(),
|
||||
)
|
||||
when:
|
||||
new Thread({ Thread.sleep(50); upstream.head.start() }).start()
|
||||
def h = upstream.head.getFlux().next().block(Duration.ofSeconds(1))
|
||||
then:
|
||||
callData.chain == Chain.ETHEREUM__MAINNET.id
|
||||
upstream.status == UpstreamAvailability.OK
|
||||
upstream.getBuildInfo() == buildInfo
|
||||
h.hash == BlockId.from("0x50d26e119968e791970d84a7bf5d0ec474d3ec2ef85d5ec8915210ac6bc09ad7")
|
||||
}
|
||||
|
||||
def "Follows difficulty, ignores less difficult"() {
|
||||
setup:
|
||||
def api = TestingCommons.api()
|
||||
def block1 = new BlockJson().with {
|
||||
it.number = 650246
|
||||
it.hash = BlockHash.from("0x50d26e119968e791970d84a7bf5d0ec474d3ec2ef85d5ec8915210ac6bc09ad7")
|
||||
it.totalDifficulty = new BigInteger("35bbde5595de6456", 16)
|
||||
it.timestamp = Instant.now()
|
||||
it.parentHash = parent
|
||||
return it
|
||||
}
|
||||
def block2 = new BlockJson().with {
|
||||
it.number = 650247
|
||||
it.hash = BlockHash.from("0x3ec2ebf5d0ec474d0ac6bc50d2770d8409ad76e119968e7919f85d5ec891521a")
|
||||
it.totalDifficulty = new BigInteger("35bbde5595de6455", 16)
|
||||
it.timestamp = Instant.now()
|
||||
it.parentHash = parent
|
||||
return it
|
||||
}
|
||||
api.answer("eth_getBlockByHash", [block1.hash.toHex(), false], block1)
|
||||
api.answer("eth_getBlockByHash", [block2.hash.toHex(), false], block2)
|
||||
def client = mockServer.clientForServer(new BlockchainGrpc.BlockchainImplBase() {
|
||||
@Override
|
||||
void nativeCall(BlockchainOuterClass.NativeCallRequest request, StreamObserver<BlockchainOuterClass.NativeCallReplyItem> responseObserver) {
|
||||
api.nativeCall(request, responseObserver)
|
||||
}
|
||||
|
||||
@Override
|
||||
void subscribeHead(Common.Chain request, StreamObserver<BlockchainOuterClass.ChainHead> responseObserver) {
|
||||
new Thread({
|
||||
responseObserver.onNext(
|
||||
BlockchainOuterClass.ChainHead.newBuilder()
|
||||
.setBlockId(block1.hash.toHex().substring(2))
|
||||
.setHeight(block1.number)
|
||||
.setParentBlockId(parent.toHex().substring(2))
|
||||
.setWeight(ByteString.copyFrom(block1.totalDifficulty.toByteArray()))
|
||||
.build()
|
||||
)
|
||||
Thread.sleep(100)
|
||||
responseObserver.onNext(
|
||||
BlockchainOuterClass.ChainHead.newBuilder()
|
||||
.setBlockId(block2.hash.toHex().substring(2))
|
||||
.setHeight(block2.number)
|
||||
.setParentBlockId(parent.toHex().substring(2))
|
||||
.setWeight(ByteString.copyFrom(block2.totalDifficulty.toByteArray()))
|
||||
.build()
|
||||
)
|
||||
}).start()
|
||||
}
|
||||
})
|
||||
def upstream = new EthereumGrpcUpstream("test", hash, UpstreamsConfig.UpstreamRole.PRIMARY, Chain.ETHEREUM__MAINNET, client, new JsonRpcGrpcClient(client, Chain.ETHEREUM__MAINNET, metrics), null, ChainsConfig.ChainConfig.default(), Schedulers.boundedElastic())
|
||||
upstream.setLag(0)
|
||||
upstream.update(
|
||||
BlockchainOuterClass.DescribeChain.newBuilder()
|
||||
.setStatus(BlockchainOuterClass.ChainStatus.newBuilder().setQuorum(1).setAvailabilityValue(UpstreamAvailability.OK.grpcId))
|
||||
.addAllSupportedMethods(["eth_getBlockByHash"])
|
||||
.build(),
|
||||
BlockchainOuterClass.BuildInfo.newBuilder()
|
||||
.setVersion(buildInfo.version)
|
||||
.build(),
|
||||
)
|
||||
when:
|
||||
new Thread({ Thread.sleep(50); upstream.head.start() }).start()
|
||||
def h = upstream.head.getFlux().take(Duration.ofSeconds(1)).last().block(Duration.ofSeconds(2))
|
||||
then:
|
||||
upstream.status == UpstreamAvailability.OK
|
||||
upstream.getBuildInfo() == buildInfo
|
||||
h.hash == BlockId.from("0x50d26e119968e791970d84a7bf5d0ec474d3ec2ef85d5ec8915210ac6bc09ad7")
|
||||
h.height == 650246
|
||||
}
|
||||
|
||||
def "Follows difficulty"() {
|
||||
setup:
|
||||
def callData = [:]
|
||||
def finished = new CompletableFuture<Boolean>()
|
||||
def chain = Chain.ETHEREUM__MAINNET
|
||||
def api = TestingCommons.api()
|
||||
def block1 = new BlockJson().with {
|
||||
it.number = 650246
|
||||
it.hash = BlockHash.from("0x50d26e119968e791970d84a7bf5d0ec474d3ec2ef85d5ec8915210ac6bc09ad7")
|
||||
it.totalDifficulty = new BigInteger("35bbde5595de6456", 16)
|
||||
it.timestamp = Instant.now()
|
||||
it.parentHash = parent
|
||||
return it
|
||||
}
|
||||
def block2 = new BlockJson().with {
|
||||
it.number = 650247
|
||||
it.hash = BlockHash.from("0x3ec2ebf5d0ec474d0ac6bc50d2770d8409ad76e119968e7919f85d5ec891521a")
|
||||
it.totalDifficulty = new BigInteger("35bbde5595de6457", 16)
|
||||
it.timestamp = Instant.now()
|
||||
it.parentHash = parent
|
||||
return it
|
||||
}
|
||||
api.answer("eth_getBlockByHash", [block1.hash.toHex(), false], block1)
|
||||
api.answer("eth_getBlockByHash", [block2.hash.toHex(), false], block2)
|
||||
def client = mockServer.clientForServer(new BlockchainGrpc.BlockchainImplBase() {
|
||||
@Override
|
||||
void nativeCall(BlockchainOuterClass.NativeCallRequest request, StreamObserver<BlockchainOuterClass.NativeCallReplyItem> responseObserver) {
|
||||
api.nativeCall(request, responseObserver)
|
||||
}
|
||||
|
||||
@Override
|
||||
void subscribeHead(Common.Chain request, StreamObserver<BlockchainOuterClass.ChainHead> responseObserver) {
|
||||
responseObserver.onNext(
|
||||
BlockchainOuterClass.ChainHead.newBuilder()
|
||||
.setBlockId(block1.hash.toHex().substring(2))
|
||||
.setHeight(block1.number)
|
||||
.setParentBlockId(parent.toHex().substring(2))
|
||||
.setWeight(ByteString.copyFrom(block1.totalDifficulty.toByteArray()))
|
||||
.build()
|
||||
)
|
||||
responseObserver.onNext(
|
||||
BlockchainOuterClass.ChainHead.newBuilder()
|
||||
.setBlockId(block2.hash.toHex().substring(2))
|
||||
.setHeight(block2.number)
|
||||
.setParentBlockId(parent.toHex().substring(2))
|
||||
.setWeight(ByteString.copyFrom(block2.totalDifficulty.toByteArray()))
|
||||
.build()
|
||||
)
|
||||
finished.complete(true)
|
||||
}
|
||||
})
|
||||
def upstream = new EthereumGrpcUpstream("test", hash, UpstreamsConfig.UpstreamRole.PRIMARY, chain, client, new JsonRpcGrpcClient(client, chain, metrics), null, ChainsConfig.ChainConfig.default(), Schedulers.boundedElastic())
|
||||
upstream.setLag(0)
|
||||
upstream.update(
|
||||
BlockchainOuterClass.DescribeChain.newBuilder()
|
||||
.setStatus(BlockchainOuterClass.ChainStatus.newBuilder().setQuorum(1).setAvailabilityValue(UpstreamAvailability.OK.grpcId))
|
||||
.addAllSupportedMethods(["eth_getBlockByHash"])
|
||||
.build(),
|
||||
BlockchainOuterClass.BuildInfo.newBuilder()
|
||||
.setVersion(buildInfo.version)
|
||||
.build(),
|
||||
)
|
||||
when:
|
||||
new Thread({ Thread.sleep(50); upstream.head.start() }).start()
|
||||
finished.get()
|
||||
def h = upstream.head.getFlux().take(Duration.ofSeconds(1)).last().block(Duration.ofSeconds(2))
|
||||
then:
|
||||
upstream.status == UpstreamAvailability.OK
|
||||
upstream.getBuildInfo() == buildInfo
|
||||
h.hash == BlockId.from("0x3ec2ebf5d0ec474d0ac6bc50d2770d8409ad76e119968e7919f85d5ec891521a")
|
||||
h.height == 650247
|
||||
}
|
||||
|
||||
private BlockchainOuterClass.DescribeChain describe(List<String> methods) {
|
||||
return BlockchainOuterClass.DescribeChain.newBuilder()
|
||||
.setStatus(BlockchainOuterClass.ChainStatus.newBuilder().setQuorum(1).setAvailabilityValue(UpstreamAvailability.OK.grpcId))
|
||||
.addAllSupportedMethods(methods)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user