problem: Spring Reactor is too outdated

This commit is contained in:
Igor Artamonov
2021-05-05 14:39:43 -04:00
parent 053bdc9549
commit adfc35e994
9 changed files with 62 additions and 53 deletions

View File

@@ -45,6 +45,7 @@ java {
repositories { repositories {
mavenLocal() mavenLocal()
mavenCentral() mavenCentral()
jcenter()
maven { url "https://repo.spring.io/snapshot" } maven { url "https://repo.spring.io/snapshot" }
maven { url "https://repo.spring.io/milestone" } maven { url "https://repo.spring.io/milestone" }
maven { url "https://dl.bintray.com/infinitape/etherjar" } maven { url "https://dl.bintray.com/infinitape/etherjar" }
@@ -61,7 +62,7 @@ configurations {
} }
dependencies { dependencies {
implementation "io.emeraldpay:emerald-api:0.9.1" implementation "io.emeraldpay:emerald-api:0.9.2"
implementation "io.grpc:grpc-protobuf:${grpcVersion}" implementation "io.grpc:grpc-protobuf:${grpcVersion}"
implementation "io.grpc:grpc-stub:${grpcVersion}" implementation "io.grpc:grpc-stub:${grpcVersion}"
@@ -83,15 +84,16 @@ dependencies {
implementation "org.springframework.security:spring-security-web:$springSecurtyVersion" implementation "org.springframework.security:spring-security-web:$springSecurtyVersion"
implementation "org.springframework.security:spring-security-config:$springSecurtyVersion" implementation "org.springframework.security:spring-security-config:$springSecurtyVersion"
implementation "io.projectreactor:reactor-core:$reactorVersion" implementation "io.projectreactor:reactor-core:$reactorVersion"
implementation "io.projectreactor.netty:reactor-netty:0.9.7.RELEASE" implementation "io.projectreactor.netty:reactor-netty:1.0.6"
implementation 'io.projectreactor.addons:reactor-extra:3.3.3.RELEASE' implementation 'io.projectreactor.addons:reactor-extra:3.4.3'
implementation 'io.projectreactor.kotlin:reactor-kotlin-extensions:1.0.2.RELEASE' implementation 'io.projectreactor.kotlin:reactor-kotlin-extensions:1.1.3'
implementation "com.salesforce.servicelibs:reactor-grpc-stub:$reactiveGrpcVersion" implementation "com.salesforce.servicelibs:reactor-grpc-stub:$reactiveGrpcVersion"
implementation 'io.micrometer:micrometer-registry-prometheus:1.5.6' implementation 'io.micrometer:micrometer-registry-prometheus:1.5.6'
implementation 'io.lettuce:lettuce-core:5.2.2.RELEASE' implementation 'io.lettuce:lettuce-core:5.2.2.RELEASE'
implementation "io.infinitape:etherjar-domain:$etherjarVersion" implementation "io.infinitape:etherjar-domain:$etherjarVersion"
implementation "io.infinitape:etherjar-hex:$etherjarVersion" implementation "io.infinitape:etherjar-hex:$etherjarVersion"
implementation "io.infinitape:etherjar-rpc-api:$etherjarVersion"
implementation "io.infinitape:etherjar-rpc-http:$etherjarVersion" implementation "io.infinitape:etherjar-rpc-http:$etherjarVersion"
implementation "io.infinitape:etherjar-rpc-ws:$etherjarVersion" implementation "io.infinitape:etherjar-rpc-ws:$etherjarVersion"
implementation "io.infinitape:etherjar-tx:$etherjarVersion" implementation "io.infinitape:etherjar-tx:$etherjarVersion"

View File

@@ -7,10 +7,10 @@ slf4jVersion=1.7.25
jacksonVersion=2.11.0 jacksonVersion=2.11.0
grpcVersion=1.25.0 grpcVersion=1.25.0
reactiveGrpcVersion=1.0.1 reactiveGrpcVersion=1.0.1
springBootVersion=2.3.5.RELEASE springBootVersion=2.4.5
springVersion=5.2.6.RELEASE springVersion=5.3.6
springSecurtyVersion=5.3.2.RELEASE springSecurtyVersion=5.4.6
reactorVersion=3.3.5.RELEASE reactorVersion=3.4.5
nettyVersion=4.1.53.Final nettyVersion=4.1.53.Final
# Our Libs # Our Libs
etherjarVersion=0.10.2 etherjarVersion=0.10.2

View File

@@ -92,10 +92,8 @@ class ProxyServer(
} }
log.info("Listening Proxy on ${config.host}:${config.port}") log.info("Listening Proxy on ${config.host}:${config.port}")
var serverBuilder = HttpServer.create() var serverBuilder = HttpServer.create()
.tcpConfiguration { .doOnChannelInit { _, channel, _ ->
it.bootstrap { b -> channel.pipeline().addFirst(errorHandler)
b.handler(errorHandler)
}
} }
.host(config.host) .host(config.host)
.port(config.port) .port(config.port)

View File

@@ -24,6 +24,7 @@ import io.emeraldpay.dshackle.upstream.Upstream
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcException import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcException
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
import io.emeraldpay.grpc.Chain
import io.infinitape.etherjar.rpc.RpcException import io.infinitape.etherjar.rpc.RpcException
import reactor.core.publisher.Mono import reactor.core.publisher.Mono
import reactor.test.StepVerifier import reactor.test.StepVerifier
@@ -43,6 +44,7 @@ class QuorumRpcReaderSpec extends Specification {
} }
} }
def apis = new FilteredApis( def apis = new FilteredApis(
Chain.ETHEREUM,
[up], Selector.empty [up], Selector.empty
) )
def reader = new QuorumRpcReader(apis, new AlwaysQuorum()) def reader = new QuorumRpcReader(apis, new AlwaysQuorum())
@@ -73,6 +75,7 @@ class QuorumRpcReaderSpec extends Specification {
_ * getApi() >> api _ * getApi() >> api
} }
def apis = new FilteredApis( def apis = new FilteredApis(
Chain.ETHEREUM,
[up], Selector.empty [up], Selector.empty
) )
def reader = new QuorumRpcReader(apis, new AlwaysQuorum()) def reader = new QuorumRpcReader(apis, new AlwaysQuorum())
@@ -104,6 +107,7 @@ class QuorumRpcReaderSpec extends Specification {
} }
} }
def apis = new FilteredApis( def apis = new FilteredApis(
Chain.ETHEREUM,
[up], Selector.empty [up], Selector.empty
) )
def reader = new QuorumRpcReader(apis, new NonEmptyQuorum(3)) def reader = new QuorumRpcReader(apis, new NonEmptyQuorum(3))
@@ -135,6 +139,7 @@ class QuorumRpcReaderSpec extends Specification {
} }
} }
def apis = new FilteredApis( def apis = new FilteredApis(
Chain.ETHEREUM,
[up], Selector.empty [up], Selector.empty
) )
def reader = new QuorumRpcReader(apis, new NonEmptyQuorum(3)) def reader = new QuorumRpcReader(apis, new NonEmptyQuorum(3))
@@ -166,6 +171,7 @@ class QuorumRpcReaderSpec extends Specification {
} }
} }
def apis = new FilteredApis( def apis = new FilteredApis(
Chain.ETHEREUM,
[up], Selector.empty [up], Selector.empty
) )
def reader = new QuorumRpcReader(apis, new NonEmptyQuorum(3)) def reader = new QuorumRpcReader(apis, new NonEmptyQuorum(3))
@@ -198,6 +204,7 @@ class QuorumRpcReaderSpec extends Specification {
_ * getApi() >> api _ * getApi() >> api
} }
def apis = new FilteredApis( def apis = new FilteredApis(
Chain.ETHEREUM,
[up], Selector.empty [up], Selector.empty
) )
def reader = new QuorumRpcReader(apis, new NonEmptyQuorum(3)) def reader = new QuorumRpcReader(apis, new NonEmptyQuorum(3))
@@ -227,6 +234,7 @@ class QuorumRpcReaderSpec extends Specification {
} }
} }
def apis = new FilteredApis( def apis = new FilteredApis(
Chain.ETHEREUM,
[up], Selector.empty [up], Selector.empty
) )
def reader = new QuorumRpcReader(apis, new NotLaggingQuorum(1)) def reader = new QuorumRpcReader(apis, new NotLaggingQuorum(1))

View File

@@ -36,7 +36,7 @@ import org.bitcoinj.params.MainNetParams
import org.bitcoinj.params.TestNet3Params import org.bitcoinj.params.TestNet3Params
import reactor.core.publisher.Flux import reactor.core.publisher.Flux
import reactor.core.publisher.Mono import reactor.core.publisher.Mono
import reactor.core.publisher.TopicProcessor import reactor.core.publisher.Sinks
import reactor.test.StepVerifier import reactor.test.StepVerifier
import spock.lang.Specification import spock.lang.Specification
@@ -267,13 +267,13 @@ class TrackBitcoinAddressSpec extends Specification {
def "Get update for a balance"() { def "Get update for a balance"() {
setup: setup:
def blocks = TopicProcessor.create() def blocks = Sinks.many().unicast().onBackpressureBuffer()
Head head = Mock(Head) { Head head = Mock(Head) {
1 * getFlux() >> Flux.concat( 1 * getFlux() >> Flux.concat(
Flux.just( Flux.just(
new BlockContainer(0L, BlockId.from(hash1), BigInteger.ZERO, Instant.now(), false, null, null, []) new BlockContainer(0L, BlockId.from(hash1), BigInteger.ZERO, Instant.now(), false, null, null, [])
), ),
Flux.from(blocks) blocks.asFlux()
) )
} }
def upstream = null def upstream = null
@@ -312,11 +312,11 @@ class TrackBitcoinAddressSpec extends Specification {
StepVerifier.create(resp) StepVerifier.create(resp)
.expectNext("0") .expectNext("0")
.then { .then {
blocks.onNext(new BlockContainer(1L, BlockId.from(hash1), BigInteger.ONE, Instant.now(), false, null, null, [])) blocks.tryEmitNext(new BlockContainer(1L, BlockId.from(hash1), BigInteger.ONE, Instant.now(), false, null, null, []))
} }
.expectNext("1230000") .expectNext("1230000")
.then { .then {
blocks.onComplete() blocks.tryEmitComplete()
} }
.expectComplete() .expectComplete()
.verify(Duration.ofSeconds(1)) .verify(Duration.ofSeconds(1))

View File

@@ -22,11 +22,11 @@ import org.jetbrains.annotations.NotNull
import org.reactivestreams.Publisher import org.reactivestreams.Publisher
import reactor.core.publisher.Flux import reactor.core.publisher.Flux
import reactor.core.publisher.Mono import reactor.core.publisher.Mono
import reactor.core.publisher.TopicProcessor import reactor.core.publisher.Sinks
class EthereumHeadMock implements Head { class EthereumHeadMock implements Head {
private TopicProcessor<BlockContainer> bus = TopicProcessor.create() private Sinks.Many<BlockContainer> bus = Sinks.many().multicast().onBackpressureBuffer()
private Publisher<BlockContainer> predefined = null private Publisher<BlockContainer> predefined = null
private BlockContainer latest private BlockContainer latest
private List<Runnable> handlers = [] private List<Runnable> handlers = []
@@ -38,7 +38,7 @@ class EthereumHeadMock implements Head {
assert block != null assert block != null
println("New block: ${block.height} / ${block.hash}") println("New block: ${block.height} / ${block.hash}")
latest = block latest = block
bus.onNext(block) bus.tryEmitNext(block)
} }
void setPredefined(Publisher<BlockContainer> predefined) { void setPredefined(Publisher<BlockContainer> predefined) {
@@ -54,7 +54,7 @@ class EthereumHeadMock implements Head {
if (predefined != null) { if (predefined != null) {
return Flux.concat(Mono.justOrEmpty(latest), Flux.from(predefined)) return Flux.concat(Mono.justOrEmpty(latest), Flux.from(predefined))
} else { } else {
return Flux.concat(Mono.justOrEmpty(latest), bus).distinctUntilChanged() return Flux.concat(Mono.justOrEmpty(latest), bus.asFlux()).distinctUntilChanged()
} }
} }

View File

@@ -18,7 +18,7 @@ package io.emeraldpay.dshackle.upstream
import io.emeraldpay.dshackle.data.BlockContainer import io.emeraldpay.dshackle.data.BlockContainer
import io.emeraldpay.dshackle.data.BlockId import io.emeraldpay.dshackle.data.BlockId
import reactor.core.publisher.Flux import reactor.core.publisher.Flux
import reactor.core.publisher.TopicProcessor import reactor.core.publisher.Sinks
import reactor.test.StepVerifier import reactor.test.StepVerifier
import spock.lang.Specification import spock.lang.Specification
@@ -35,28 +35,28 @@ class AbstractHeadSpec extends Specification {
def "Calls beforeBlock on each block"() { def "Calls beforeBlock on each block"() {
setup: setup:
TopicProcessor<BlockContainer> source = TopicProcessor.create() Sinks.Many<BlockContainer> source = Sinks.many().unicast().onBackpressureBuffer()
def head = new TestHead() def head = new TestHead()
def called = false def called = false
when: when:
head.follow(Flux.from(source)) head.follow(source.asFlux())
head.onBeforeBlock { head.onBeforeBlock {
called = true called = true
} }
def act = head.flux def act = head.flux
source.onNext(blocks[0]) source.tryEmitNext(blocks[0])
then: then:
StepVerifier.create(act) StepVerifier.create(act)
.expectNext(blocks[0]) .expectNext(blocks[0])
.then { .then {
assert called assert called
called = false called = false
source.onNext(blocks[1]) source.tryEmitNext(blocks[1])
} }
.expectNext(blocks[1]) .expectNext(blocks[1])
.then { .then {
assert called assert called
source.onComplete() source.tryEmitComplete()
} }
.expectComplete() .expectComplete()
.verify(Duration.ofSeconds(1)) .verify(Duration.ofSeconds(1))
@@ -64,29 +64,29 @@ class AbstractHeadSpec extends Specification {
def "Follows source"() { def "Follows source"() {
setup: setup:
TopicProcessor<BlockContainer> source = TopicProcessor.create() Sinks.Many<BlockContainer> source = Sinks.many().unicast().onBackpressureBuffer()
def head = new TestHead() def head = new TestHead()
when: when:
head.follow(Flux.from(source)) head.follow(source.asFlux())
def act = head.flux def act = head.flux
source.onNext(blocks[0]) source.tryEmitNext(blocks[0])
then: then:
StepVerifier.create(act) StepVerifier.create(act)
.expectNext(blocks[0]) .expectNext(blocks[0])
.then { source.onNext(blocks[1]) } .then { source.tryEmitNext(blocks[1]) }
.expectNext(blocks[1]) .expectNext(blocks[1])
.then { source.onNext(blocks[2]) } .then { source.tryEmitNext(blocks[2]) }
.expectNext(blocks[2]) .expectNext(blocks[2])
.then { source.onNext(blocks[3]) } .then { source.tryEmitNext(blocks[3]) }
.expectNext(blocks[3]) .expectNext(blocks[3])
.then { source.onComplete() } .then { source.tryEmitComplete() }
.expectComplete() .expectComplete()
.verify(Duration.ofSeconds(1)) .verify(Duration.ofSeconds(1))
} }
def "Ignores block will less difficulty"() { def "Ignores block will less difficulty"() {
setup: setup:
TopicProcessor<BlockContainer> source = TopicProcessor.create() Sinks.Many<BlockContainer> source = Sinks.many().unicast().onBackpressureBuffer()
def head = new TestHead() def head = new TestHead()
def wrongblock = new BlockContainer( def wrongblock = new BlockContainer(
blocks[1].height, BlockId.from(blocks[1].hash.value.clone().tap { it[1] = 0xff as byte }), blocks[1].height, BlockId.from(blocks[1].hash.value.clone().tap { it[1] = 0xff as byte }),
@@ -95,18 +95,18 @@ class AbstractHeadSpec extends Specification {
false, null, null, [] false, null, null, []
) )
when: when:
head.follow(Flux.from(source)) head.follow(source.asFlux())
def act = head.flux def act = head.flux
source.onNext(blocks[0]) source.tryEmitNext(blocks[0])
then: then:
StepVerifier.create(act) StepVerifier.create(act)
.expectNext(blocks[0]) .expectNext(blocks[0])
.then { source.onNext(blocks[1]) } .then { source.tryEmitNext(blocks[1]) }
.expectNext(blocks[1]) .expectNext(blocks[1])
.then { source.onNext(wrongblock) } .then { source.tryEmitNext(wrongblock) }
.then { source.onNext(blocks[3]) } .then { source.tryEmitNext(blocks[3]) }
.expectNext(blocks[3]) .expectNext(blocks[3])
.then { source.onComplete() } .then { source.tryEmitComplete() }
.expectComplete() .expectComplete()
.verify(Duration.ofSeconds(1)) .verify(Duration.ofSeconds(1))
} }

View File

@@ -63,7 +63,7 @@ class FilteredApisSpec extends Specification {
it.setStatus(UpstreamAvailability.OK) it.setStatus(UpstreamAvailability.OK)
} }
when: when:
def iter = new FilteredApis(upstreams, matcher, 0, 1, 0) def iter = new FilteredApis(Chain.ETHEREUM, upstreams, matcher, 0, 1, 0)
iter.request(10) iter.request(10)
then: then:
StepVerifier.create(iter) StepVerifier.create(iter)
@@ -74,7 +74,7 @@ class FilteredApisSpec extends Specification {
.verify(Duration.ofSeconds(1)) .verify(Duration.ofSeconds(1))
when: when:
iter = new FilteredApis(upstreams, matcher, 1, 1, 0) iter = new FilteredApis(Chain.ETHEREUM, upstreams, matcher, 1, 1, 0)
iter.request(10) iter.request(10)
then: then:
StepVerifier.create(iter) StepVerifier.create(iter)
@@ -85,7 +85,7 @@ class FilteredApisSpec extends Specification {
.verify(Duration.ofSeconds(1)) .verify(Duration.ofSeconds(1))
when: when:
iter = new FilteredApis(upstreams, matcher, 1, 2, 0) iter = new FilteredApis(Chain.ETHEREUM, upstreams, matcher, 1, 2, 0)
iter.request(10) iter.request(10)
then: then:
StepVerifier.create(iter) StepVerifier.create(iter)
@@ -101,7 +101,7 @@ class FilteredApisSpec extends Specification {
def "Exponential backoff"() { def "Exponential backoff"() {
setup: setup:
def apis = new FilteredApis([], Selector.empty, 0, 1, 0) def apis = new FilteredApis(Chain.ETHEREUM, [], Selector.empty, 0, 1, 0)
expect: expect:
wait == apis.waitDuration(n).toMillis() as Integer wait == apis.waitDuration(n).toMillis() as Integer
where: where:
@@ -123,7 +123,7 @@ class FilteredApisSpec extends Specification {
@Retry @Retry
def "Backoff uses jitter"() { def "Backoff uses jitter"() {
setup: setup:
def apis = new FilteredApis([], Selector.empty, 0, 1, 20) def apis = new FilteredApis(Chain.ETHEREUM, [], Selector.empty, 0, 1, 20)
when: when:
def act = apis.waitDuration(1).toMillis() def act = apis.waitDuration(1).toMillis()
println act println act
@@ -149,7 +149,7 @@ class FilteredApisSpec extends Specification {
def up2 = TestingCommons.upstream(api2) def up2 = TestingCommons.upstream(api2)
then: then:
StepVerifier.withVirtualTime({ StepVerifier.withVirtualTime({
def apis = new FilteredApis([up1, up2], Selector.empty, 0, 4, 0) def apis = new FilteredApis(Chain.ETHEREUM, [up1, up2], Selector.empty, 0, 4, 0)
apis.request(10) apis.request(10)
return apis return apis
}) })
@@ -173,7 +173,7 @@ class FilteredApisSpec extends Specification {
TestingCommons.upstream(it) TestingCommons.upstream(it)
} }
when: when:
def act = new FilteredApis(ups, Selector.empty, 2, 1, 0) def act = new FilteredApis(Chain.ETHEREUM, ups, Selector.empty, 2, 1, 0)
act.request(10) act.request(10)
then: then:
StepVerifier.create(act) StepVerifier.create(act)
@@ -225,7 +225,8 @@ class FilteredApisSpec extends Specification {
} }
] ]
when: when:
def act = new FilteredApis([] + fallback + standard, def act = new FilteredApis(Chain.ETHEREUM,
[] + fallback + standard,
Selector.empty, 0, 3, 0) Selector.empty, 0, 3, 0)
act.request(10) act.request(10)
then: then:

View File

@@ -24,7 +24,7 @@ import io.infinitape.etherjar.domain.BlockHash
import io.infinitape.etherjar.rpc.json.BlockJson import io.infinitape.etherjar.rpc.json.BlockJson
import org.jetbrains.annotations.NotNull import org.jetbrains.annotations.NotNull
import reactor.core.publisher.Flux import reactor.core.publisher.Flux
import reactor.core.publisher.TopicProcessor import reactor.core.publisher.Sinks
import reactor.test.StepVerifier import reactor.test.StepVerifier
import reactor.util.function.Tuples import reactor.util.function.Tuples
import spock.lang.Specification import spock.lang.Specification
@@ -58,9 +58,9 @@ class HeadLagObserverSpec extends Specification {
}) })
} }
def masterBus = TopicProcessor.create() def masterBus = Sinks.many().multicast().onBackpressureBuffer()
1 * master.getFlux() >> Flux.from(masterBus) 1 * master.getFlux() >> masterBus.asFlux()
1 * head1.getFlux() >> Flux.merge( 1 * head1.getFlux() >> Flux.merge(
Flux.just(blocks[1]), Flux.just(blocks[1]),
Flux.just(blocks[2]).delaySubscription(Duration.ofSeconds(1)) Flux.just(blocks[2]).delaySubscription(Duration.ofSeconds(1))
@@ -79,7 +79,7 @@ class HeadLagObserverSpec extends Specification {
then: then:
StepVerifier.create(act) StepVerifier.create(act)
.then { masterBus.onNext(blocks[1]) } .then { masterBus.tryEmitNext(blocks[1]) }
.expectNextCount(3) .expectNextCount(3)
.verifyComplete() .verifyComplete()
} }