Update dependencies (#767)
This commit is contained in:
@@ -72,19 +72,16 @@ dependencies {
|
|||||||
implementation(libs.grpc.proto.util)
|
implementation(libs.grpc.proto.util)
|
||||||
|
|
||||||
implementation libs.micrometer.registry.prometheus
|
implementation libs.micrometer.registry.prometheus
|
||||||
|
implementation libs.micrometer.ctx.prop
|
||||||
implementation libs.lettuce.core
|
implementation libs.lettuce.core
|
||||||
|
|
||||||
implementation(libs.spring.cloud.starter.sleuth) {
|
|
||||||
exclude module: 'spring-security-rsa'
|
|
||||||
}
|
|
||||||
implementation libs.brave.instrumentation.grpc
|
implementation libs.brave.instrumentation.grpc
|
||||||
|
implementation libs.brave.ctx.slf4j
|
||||||
|
|
||||||
implementation libs.logstash.encoder
|
implementation libs.logstash.encoder
|
||||||
|
|
||||||
implementation libs.janino
|
implementation libs.janino
|
||||||
|
|
||||||
implementation libs.spring.cloud.sleuth.zipkin
|
|
||||||
|
|
||||||
implementation libs.bitcoinj
|
implementation libs.bitcoinj
|
||||||
|
|
||||||
implementation libs.snake.yaml
|
implementation libs.snake.yaml
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id 'org.jetbrains.kotlin.jvm' version '1.9.25'
|
id 'org.jetbrains.kotlin.jvm' version '2.3.0'
|
||||||
id 'maven-publish'
|
id 'maven-publish'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -12,7 +12,8 @@ group = 'dshackle'
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'org.yaml:snakeyaml:1.24'
|
implementation 'org.yaml:snakeyaml:1.24'
|
||||||
testImplementation 'org.junit.jupiter:junit-jupiter:5.9.1'
|
testImplementation 'org.junit.jupiter:junit-jupiter:6.0.1'
|
||||||
|
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||||
}
|
}
|
||||||
|
|
||||||
test {
|
test {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.0-bin.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|||||||
@@ -1,22 +1,20 @@
|
|||||||
[versions]
|
[versions]
|
||||||
detekt = "1.23.1"
|
groovy = "5.0.3"
|
||||||
groovy = "4.0.15"
|
|
||||||
protoc = "4.33.2"
|
protoc = "4.33.2"
|
||||||
jackson = "2.11.0"
|
jackson = "2.20.1"
|
||||||
grpc = "1.57.0"
|
grpc = "1.78.0"
|
||||||
reactive-grpc = "1.2.0"
|
spring-boot = "4.0.1"
|
||||||
spring-boot = "2.6.15"
|
reactor = "3.8.1"
|
||||||
spring-security = "5.5.3"
|
netty = "4.2.9.Final"
|
||||||
reactor = "3.4.32"
|
netty-tcnative = "2.0.74.Final"
|
||||||
netty = "4.1.110.Final"
|
kotlin = "2.3.0"
|
||||||
netty-tcnative = "2.0.66.Final"
|
httpcomponents = "5.5.1"
|
||||||
kotlin = "1.9.25"
|
|
||||||
httpcomponents = "4.5.8"
|
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
apache-commons-lang3 = "org.apache.commons:commons-lang3:3.9"
|
apache-commons-lang3 = "org.apache.commons:commons-lang3:3.9"
|
||||||
apache-commons-collections4 = "org.apache.commons:commons-collections4:4.3"
|
apache-commons-collections4 = "org.apache.commons:commons-collections4:4.3"
|
||||||
apache-commons-math3 = "org.apache.commons:commons-math3:3.6.1"
|
apache-commons-math3 = "org.apache.commons:commons-math3:3.6.1"
|
||||||
|
commons-codec = "commons-codec:commons-codec:1.20.0"
|
||||||
|
|
||||||
bitcoinj = "org.bitcoinj:bitcoinj-core:0.15.8"
|
bitcoinj = "org.bitcoinj:bitcoinj-core:0.15.8"
|
||||||
|
|
||||||
@@ -33,21 +31,19 @@ commons-io = "commons-io:commons-io:2.6"
|
|||||||
|
|
||||||
cglib-nodep = "cglib:cglib-nodep:3.3.0"
|
cglib-nodep = "cglib:cglib-nodep:3.3.0"
|
||||||
|
|
||||||
detekt-formatting = { module = "io.gitlab.arturbosch.detekt:detekt-formatting", version.ref = "detekt" }
|
|
||||||
|
|
||||||
equals-verifier = "nl.jqno.equalsverifier:equalsverifier:3.10.1"
|
equals-verifier = "nl.jqno.equalsverifier:equalsverifier:3.10.1"
|
||||||
|
|
||||||
groovy = { module = "org.apache.groovy:groovy", version.ref = "groovy" }
|
groovy = { module = "org.apache.groovy:groovy", version.ref = "groovy" }
|
||||||
|
|
||||||
grpc-proto-util = { module = "com.google.protobuf:protobuf-java-util", version.ref = "protoc" }
|
grpc-proto-util = { module = "com.google.protobuf:protobuf-java-util", version.ref = "protoc" }
|
||||||
grpc-protobuf = { module = "io.grpc:grpc-protobuf", version.ref = "grpc" }
|
grpc-protobuf = { module = "io.grpc:grpc-protobuf", version.ref = "grpc" }
|
||||||
|
grpc-inprocess = { module = "io.grpc:grpc-inprocess", version.ref = "grpc" }
|
||||||
grpc-stub = { module = "io.grpc:grpc-stub", version.ref = "grpc" }
|
grpc-stub = { module = "io.grpc:grpc-stub", version.ref = "grpc" }
|
||||||
grpc-netty = { module = "io.grpc:grpc-netty", version.ref = "grpc" }
|
grpc-netty = { module = "io.grpc:grpc-netty", version.ref = "grpc" }
|
||||||
grpc-testing = { module = "io.grpc:grpc-testing", version.ref = "grpc" }
|
grpc-testing = { module = "io.grpc:grpc-testing", version.ref = "grpc" }
|
||||||
grpc-services = { module = "io.grpc:grpc-services", version.ref = "grpc" }
|
grpc-services = { module = "io.grpc:grpc-services", version.ref = "grpc" }
|
||||||
|
|
||||||
httpcomponents-httpmime = { module = "org.apache.httpcomponents:httpmime", version.ref = "httpcomponents" }
|
httpcomponents-httpclient = { module = "org.apache.httpcomponents.client5:httpclient5", version.ref = "httpcomponents" }
|
||||||
httpcomponents-httpclient = { module = "org.apache.httpcomponents:httpclient", version.ref = "httpcomponents" }
|
|
||||||
|
|
||||||
jackson-core = { module = "com.fasterxml.jackson.core:jackson-core", version.ref = "jackson" }
|
jackson-core = { module = "com.fasterxml.jackson.core:jackson-core", version.ref = "jackson" }
|
||||||
jackson-databind = { module = "com.fasterxml.jackson.core:jackson-databind", version.ref = "jackson" }
|
jackson-databind = { module = "com.fasterxml.jackson.core:jackson-databind", version.ref = "jackson" }
|
||||||
@@ -65,11 +61,12 @@ kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref =
|
|||||||
|
|
||||||
lettuce-core = "io.lettuce:lettuce-core:5.2.2.RELEASE"
|
lettuce-core = "io.lettuce:lettuce-core:5.2.2.RELEASE"
|
||||||
|
|
||||||
micrometer-registry-prometheus = "io.micrometer:micrometer-registry-prometheus:1.10.0"
|
micrometer-registry-prometheus = "io.micrometer:micrometer-registry-prometheus:1.16.0"
|
||||||
|
micrometer-ctx-prop = "io.micrometer:context-propagation:1.2.0"
|
||||||
|
|
||||||
mockserver-netty = "org.mock-server:mockserver-netty:5.11.2"
|
mockserver-netty = "org.mock-server:mockserver-netty:5.15.0"
|
||||||
|
|
||||||
mockito-kotlin = "org.mockito.kotlin:mockito-kotlin:5.1.0"
|
mockito-kotlin = "org.mockito.kotlin:mockito-kotlin:6.1.0"
|
||||||
|
|
||||||
netty-common = { module = "io.netty:netty-common", version.ref = "netty" }
|
netty-common = { module = "io.netty:netty-common", version.ref = "netty" }
|
||||||
netty-transport = { module = "io.netty:netty-transport", version.ref = "netty" }
|
netty-transport = { module = "io.netty:netty-transport", version.ref = "netty" }
|
||||||
@@ -90,8 +87,9 @@ zeromq = "org.zeromq:jeromq:0.5.2"
|
|||||||
objgenesis = "org.objenesis:objenesis:3.1"
|
objgenesis = "org.objenesis:objenesis:3.1"
|
||||||
|
|
||||||
reactor-core = { module = "io.projectreactor:reactor-core", version.ref = "reactor" }
|
reactor-core = { module = "io.projectreactor:reactor-core", version.ref = "reactor" }
|
||||||
reactor-netty = { module = "io.projectreactor.netty:reactor-netty", version = "1.1.10" }
|
reactor-micrometer = { module = "io.projectreactor:reactor-core-micrometer", version.ref = "reactor" }
|
||||||
reactor-extra = { module = "io.projectreactor.addons:reactor-extra", version = "3.5.1" }
|
reactor-netty = { module = "io.projectreactor.netty:reactor-netty", version = "1.3.1" }
|
||||||
|
reactor-extra = { module = "io.projectreactor.addons:reactor-extra", version = "3.6.0" }
|
||||||
reactor-kotlin = { module = "io.projectreactor.kotlin:reactor-kotlin-extensions", version = "1.1.7" }
|
reactor-kotlin = { module = "io.projectreactor.kotlin:reactor-kotlin-extensions", version = "1.1.7" }
|
||||||
reactor-test = { module = "io.projectreactor:reactor-test", version.ref = "reactor" }
|
reactor-test = { module = "io.projectreactor:reactor-test", version.ref = "reactor" }
|
||||||
|
|
||||||
@@ -99,24 +97,20 @@ reactor-grpc-stub = "com.salesforce.servicelibs:reactor-grpc-stub:1.2.0"
|
|||||||
|
|
||||||
snake-yaml = "org.yaml:snakeyaml:1.24"
|
snake-yaml = "org.yaml:snakeyaml:1.24"
|
||||||
|
|
||||||
spockframework-core = "org.spockframework:spock-core:2.3-groovy-4.0"
|
spockframework-core = "org.spockframework:spock-core:2.4-groovy-5.0"
|
||||||
|
|
||||||
spring-boot-starter = { module = "org.springframework.boot:spring-boot-starter", version.ref = "spring-boot" }
|
spring-boot-starter = { module = "org.springframework.boot:spring-boot-starter", version.ref = "spring-boot" }
|
||||||
spring-security-core = { module = "org.springframework.security:spring-security-core", version.ref = "spring-security" }
|
spring-boot-starter-actuator = { module = "org.springframework.boot:spring-boot-starter-actuator", version.ref = "spring-boot" }
|
||||||
spring-security-web = { module = "org.springframework.security:spring-security-web", version.ref = "spring-security" }
|
|
||||||
spring-security-config = { module = "org.springframework.security:spring-security-config", version.ref = "spring-security" }
|
|
||||||
|
|
||||||
spring-boot-starter-test = { module = "org.springframework.boot:spring-boot-starter-test", version.ref = "spring-boot" }
|
spring-boot-starter-test = { module = "org.springframework.boot:spring-boot-starter-test", version.ref = "spring-boot" }
|
||||||
|
|
||||||
testcontainers = "org.testcontainers:testcontainers:1.21.3"
|
testcontainers = "org.testcontainers:testcontainers:1.21.3"
|
||||||
testcontainers-ganache = "io.github.ganchix:testcontainers-java-module-ganache:0.0.4"
|
testcontainers-ganache = "io.github.ganchix:testcontainers-java-module-ganache:0.0.4"
|
||||||
|
|
||||||
junit-jupiter = "org.junit.jupiter:junit-jupiter:5.9.1"
|
|
||||||
assertj = "org.assertj:assertj-core:3.23.1"
|
assertj = "org.assertj:assertj-core:3.23.1"
|
||||||
|
|
||||||
spring-cloud-starter-sleuth = "org.springframework.cloud:spring-cloud-starter-sleuth:3.1.6"
|
brave-instrumentation-grpc = "io.zipkin.brave:brave-instrumentation-grpc:6.3.0"
|
||||||
spring-cloud-sleuth-zipkin = "org.springframework.cloud:spring-cloud-sleuth-zipkin:3.1.6"
|
brave-ctx-slf4j = "io.zipkin.brave:brave-context-slf4j:6.3.0"
|
||||||
brave-instrumentation-grpc = "io.zipkin.brave:brave-instrumentation-grpc:5.15.0"
|
|
||||||
|
|
||||||
auth0-jwt = "com.auth0:java-jwt:4.4.0"
|
auth0-jwt = "com.auth0:java-jwt:4.4.0"
|
||||||
|
|
||||||
@@ -125,24 +119,23 @@ mockito-inline = "org.mockito:mockito-inline:4.0.0"
|
|||||||
semver4j = "com.vdurmont:semver4j:3.1.0"
|
semver4j = "com.vdurmont:semver4j:3.1.0"
|
||||||
|
|
||||||
[bundles]
|
[bundles]
|
||||||
apache-commons = ["commons-io", "apache-commons-lang3", "apache-commons-collections4", "apache-commons-math3"]
|
apache-commons = ["commons-io", "apache-commons-lang3", "apache-commons-collections4", "apache-commons-math3", "commons-codec"]
|
||||||
grpc = ["grpc-protobuf", "grpc-stub", "grpc-netty", "grpc-proto-util", "grpc-services"]
|
grpc = ["grpc-protobuf", "grpc-stub", "grpc-netty", "grpc-proto-util", "grpc-services", "grpc-inprocess"]
|
||||||
httpcomponents = ["httpcomponents-httpmime", "httpcomponents-httpclient"]
|
httpcomponents = ["httpcomponents-httpclient"]
|
||||||
jackson = ["jackson-core", "jackson-databind", "jackson-datatype-jdk8", "jackson-datatype-jsr310", "jackson-module-kotlin", "jackson-yaml"]
|
jackson = ["jackson-core", "jackson-databind", "jackson-datatype-jdk8", "jackson-datatype-jsr310", "jackson-module-kotlin", "jackson-yaml"]
|
||||||
kotlin = ["kotlin-stdlib-jdk8", "kotlin-reflect"]
|
kotlin = ["kotlin-stdlib-jdk8", "kotlin-reflect"]
|
||||||
netty = ["netty-common", "netty-transport", "netty-handler-core", "netty-handler-proxy", "netty-resolver-core", "netty-resolver-dns", "netty-codec-core", "netty-codec-http", "netty-codec-http2", "netty-buffer", "netty-tcnative-core"]
|
netty = ["netty-common", "netty-transport", "netty-handler-core", "netty-handler-proxy", "netty-resolver-core", "netty-resolver-dns", "netty-codec-core", "netty-codec-http", "netty-codec-http2", "netty-buffer", "netty-tcnative-core"]
|
||||||
reactor = ["reactor-core", "reactor-netty", "reactor-extra", "reactor-kotlin"]
|
reactor = ["reactor-core", "reactor-netty", "reactor-extra", "reactor-kotlin", "reactor-micrometer"]
|
||||||
spring-framework = ["spring-boot-starter", "spring-security-core", "spring-security-web", "spring-security-config"]
|
spring-framework = ["spring-boot-starter", "spring-boot-starter-actuator"]
|
||||||
testcontainers = ["testcontainers", "testcontainers-ganache"]
|
testcontainers = ["testcontainers", "testcontainers-ganache"]
|
||||||
junit = ["junit-jupiter", "assertj"]
|
junit = ["assertj"]
|
||||||
bouncycastle = ["bouncycastle-pkix", "bouncycastle-prov"]
|
bouncycastle = ["bouncycastle-pkix", "bouncycastle-prov"]
|
||||||
|
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
||||||
jib = { id = "com.google.cloud.tools.jib", version = "3.4.3" }
|
jib = { id = "com.google.cloud.tools.jib", version = "3.5.2" }
|
||||||
spring = { id = "org.springframework.boot", version = "2.6.0" }
|
spring = { id = "org.springframework.boot", version = "4.0.1" }
|
||||||
git = { id = "com.palantir.git-version", version = "0.12.3" }
|
git = { id = "com.palantir.git-version", version = "0.12.3" }
|
||||||
protobuf = { id = "com.google.protobuf", version = "0.9.1" }
|
protobuf = { id = "com.google.protobuf", version = "0.9.6" }
|
||||||
ktlint = { id = "org.jlleitschuh.gradle.ktlint", version = "11.6.0" }
|
ktlint = { id = "org.jlleitschuh.gradle.ktlint", version = "11.6.0" }
|
||||||
detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" }
|
|
||||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,5 +1,5 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.0-bin.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|||||||
@@ -25,10 +25,11 @@ import io.grpc.ServerCall
|
|||||||
import io.grpc.ServerCallHandler
|
import io.grpc.ServerCallHandler
|
||||||
import io.grpc.ServerInterceptor
|
import io.grpc.ServerInterceptor
|
||||||
import io.grpc.netty.NettyServerBuilder
|
import io.grpc.netty.NettyServerBuilder
|
||||||
import io.grpc.protobuf.services.ProtoReflectionService
|
import io.grpc.protobuf.services.ProtoReflectionServiceV1
|
||||||
import io.micrometer.core.instrument.Metrics
|
import io.micrometer.core.instrument.Metrics
|
||||||
import io.micrometer.core.instrument.Tag
|
|
||||||
import io.micrometer.core.instrument.binder.jvm.ExecutorServiceMetrics
|
import io.micrometer.core.instrument.binder.jvm.ExecutorServiceMetrics
|
||||||
|
import jakarta.annotation.PostConstruct
|
||||||
|
import jakarta.annotation.PreDestroy
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.beans.factory.annotation.Value
|
import org.springframework.beans.factory.annotation.Value
|
||||||
import org.springframework.scheduling.concurrent.CustomizableThreadFactory
|
import org.springframework.scheduling.concurrent.CustomizableThreadFactory
|
||||||
@@ -36,8 +37,6 @@ import org.springframework.stereotype.Service
|
|||||||
import java.net.InetSocketAddress
|
import java.net.InetSocketAddress
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.annotation.PostConstruct
|
|
||||||
import javax.annotation.PreDestroy
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
open class GrpcServer(
|
open class GrpcServer(
|
||||||
@@ -103,21 +102,16 @@ open class GrpcServer(
|
|||||||
serverBuilder.addService(it)
|
serverBuilder.addService(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
serverBuilder.addService(ProtoReflectionService.newInstance())
|
serverBuilder.addService(ProtoReflectionServiceV1.newInstance())
|
||||||
|
|
||||||
val pool = Executors.newFixedThreadPool(20, CustomizableThreadFactory("fixed-grpc-"))
|
val pool = Executors.newFixedThreadPool(20, CustomizableThreadFactory("fixed-grpc-"))
|
||||||
|
|
||||||
serverBuilder.executor(
|
serverBuilder.executor(
|
||||||
if (mainConfig.monitoring.enableExtended) {
|
ExecutorServiceMetrics.monitor(
|
||||||
ExecutorServiceMetrics.monitor(
|
Metrics.globalRegistry,
|
||||||
Metrics.globalRegistry,
|
pool,
|
||||||
pool,
|
"fixed-grpc-executor",
|
||||||
"fixed-grpc-executor",
|
),
|
||||||
Tag.of("reactor_scheduler_id", "_"),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
pool
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
val server = serverBuilder.build()
|
val server = serverBuilder.build()
|
||||||
|
|||||||
@@ -17,32 +17,28 @@
|
|||||||
package io.emeraldpay.dshackle
|
package io.emeraldpay.dshackle
|
||||||
|
|
||||||
import io.emeraldpay.dshackle.config.MainConfig
|
import io.emeraldpay.dshackle.config.MainConfig
|
||||||
import io.emeraldpay.dshackle.monitoring.MonitoringSetup
|
|
||||||
import io.emeraldpay.dshackle.monitoring.accesslog.AccessHandlerHttp
|
import io.emeraldpay.dshackle.monitoring.accesslog.AccessHandlerHttp
|
||||||
import io.emeraldpay.dshackle.proxy.ProxyServer
|
import io.emeraldpay.dshackle.proxy.ProxyServer
|
||||||
import io.emeraldpay.dshackle.proxy.ReadRpcJson
|
import io.emeraldpay.dshackle.proxy.ReadRpcJson
|
||||||
import io.emeraldpay.dshackle.proxy.WriteRpcJson
|
import io.emeraldpay.dshackle.proxy.WriteRpcJson
|
||||||
import io.emeraldpay.dshackle.rpc.NativeCall
|
import io.emeraldpay.dshackle.rpc.NativeCall
|
||||||
import io.emeraldpay.dshackle.rpc.NativeSubscribe
|
import io.emeraldpay.dshackle.rpc.NativeSubscribe
|
||||||
|
import jakarta.annotation.PostConstruct
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import javax.annotation.PostConstruct
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts HTTP proxy endpoint, if configured
|
* Starts HTTP proxy endpoint, if configured
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
class ProxyStarter(
|
class ProxyStarter(
|
||||||
@Autowired private val mainConfig: MainConfig,
|
private val mainConfig: MainConfig,
|
||||||
@Autowired private val readRpcJson: ReadRpcJson,
|
private val readRpcJson: ReadRpcJson,
|
||||||
@Autowired private val writeRpcJson: WriteRpcJson,
|
private val writeRpcJson: WriteRpcJson,
|
||||||
@Autowired private val nativeCall: NativeCall,
|
private val nativeCall: NativeCall,
|
||||||
@Autowired private val nativeSubscribe: NativeSubscribe,
|
private val nativeSubscribe: NativeSubscribe,
|
||||||
@Autowired private val tlsSetup: TlsSetup,
|
private val tlsSetup: TlsSetup,
|
||||||
@Autowired private val accessHandlerHttp: AccessHandlerHttp,
|
private val accessHandlerHttp: AccessHandlerHttp,
|
||||||
// depend on Monitoring, declared here just to ensure it's properly initialized before the Proxy
|
|
||||||
@Autowired private val monitoringSetup: MonitoringSetup,
|
|
||||||
) {
|
) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -16,6 +16,10 @@
|
|||||||
*/
|
*/
|
||||||
package io.emeraldpay.dshackle
|
package io.emeraldpay.dshackle
|
||||||
|
|
||||||
|
import io.micrometer.context.ContextRegistry
|
||||||
|
import io.micrometer.context.integration.Slf4jThreadLocalAccessor
|
||||||
|
import io.micrometer.core.instrument.Metrics
|
||||||
|
import io.micrometer.core.instrument.binder.jvm.ExecutorServiceMetrics
|
||||||
import io.netty.handler.ssl.OpenSsl
|
import io.netty.handler.ssl.OpenSsl
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.boot.ResourceBanner
|
import org.springframework.boot.ResourceBanner
|
||||||
@@ -23,6 +27,9 @@ import org.springframework.boot.SpringApplication
|
|||||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||||
import org.springframework.core.io.ClassPathResource
|
import org.springframework.core.io.ClassPathResource
|
||||||
import org.springframework.core.io.support.ResourcePropertySource
|
import org.springframework.core.io.support.ResourcePropertySource
|
||||||
|
import reactor.core.Scannable
|
||||||
|
import reactor.core.Scannable.Attr
|
||||||
|
import reactor.core.publisher.Hooks
|
||||||
import reactor.core.scheduler.Schedulers
|
import reactor.core.scheduler.Schedulers
|
||||||
|
|
||||||
@SpringBootApplication(scanBasePackages = ["io.emeraldpay.dshackle"])
|
@SpringBootApplication(scanBasePackages = ["io.emeraldpay.dshackle"])
|
||||||
@@ -31,9 +38,22 @@ open class Starter
|
|||||||
private val log = LoggerFactory.getLogger(Starter::class.java)
|
private val log = LoggerFactory.getLogger(Starter::class.java)
|
||||||
|
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
|
ContextRegistry.getInstance().registerThreadLocalAccessor(Slf4jThreadLocalAccessor())
|
||||||
|
Hooks.enableAutomaticContextPropagation()
|
||||||
OpenSsl.ensureAvailability()
|
OpenSsl.ensureAvailability()
|
||||||
|
|
||||||
Schedulers.enableMetrics()
|
// add metrics for internal reactor schedulers
|
||||||
|
Schedulers.addExecutorServiceDecorator("key") { scheduler, execService ->
|
||||||
|
val schedulerName = Scannable.from(scheduler).scanOrDefault(Attr.NAME, scheduler.javaClass.name)
|
||||||
|
if (schedulerName.contains("single") || schedulerName.contains("parallel")) {
|
||||||
|
ExecutorServiceMetrics.monitor(
|
||||||
|
Metrics.globalRegistry,
|
||||||
|
execService,
|
||||||
|
schedulerName,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
execService
|
||||||
|
}
|
||||||
|
|
||||||
HeapDumpCreator.init()
|
HeapDumpCreator.init()
|
||||||
|
|
||||||
|
|||||||
@@ -24,13 +24,12 @@ import io.netty.handler.ssl.SslContextBuilder
|
|||||||
import io.netty.handler.ssl.SslProvider
|
import io.netty.handler.ssl.SslProvider
|
||||||
import org.apache.commons.lang3.StringUtils
|
import org.apache.commons.lang3.StringUtils
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import java.security.cert.CertificateFactory
|
import java.security.cert.CertificateFactory
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
open class TlsSetup(
|
open class TlsSetup(
|
||||||
@Autowired val fileResolver: FileResolver,
|
val fileResolver: FileResolver,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -24,16 +24,15 @@ import io.lettuce.core.api.StatefulRedisConnection
|
|||||||
import io.lettuce.core.codec.ByteArrayCodec
|
import io.lettuce.core.codec.ByteArrayCodec
|
||||||
import io.lettuce.core.codec.RedisCodec
|
import io.lettuce.core.codec.RedisCodec
|
||||||
import io.lettuce.core.codec.StringCodec
|
import io.lettuce.core.codec.StringCodec
|
||||||
|
import jakarta.annotation.PostConstruct
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
|
||||||
import org.springframework.stereotype.Repository
|
import org.springframework.stereotype.Repository
|
||||||
import java.util.EnumMap
|
import java.util.EnumMap
|
||||||
import javax.annotation.PostConstruct
|
|
||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
open class CachesFactory(
|
open class CachesFactory(
|
||||||
@Autowired private val cacheConfig: CacheConfig,
|
private val cacheConfig: CacheConfig,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import reactor.core.publisher.Mono
|
|||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
import java.util.concurrent.atomic.AtomicReference
|
import java.util.concurrent.atomic.AtomicReference
|
||||||
|
|
||||||
class CurrentBlockCache<K, D> : Reader<K, D> {
|
class CurrentBlockCache<K, D : Any> : Reader<K, D> {
|
||||||
|
|
||||||
private val cache = AtomicReference(ConcurrentHashMap<K, D>())
|
private val cache = AtomicReference(ConcurrentHashMap<K, D>())
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import java.time.Instant
|
|||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
abstract class OnBlockRedisCache<T>(
|
abstract class OnBlockRedisCache<T : Any>(
|
||||||
private val redis: RedisReactiveCommands<String, ByteArray>,
|
private val redis: RedisReactiveCommands<String, ByteArray>,
|
||||||
private val chain: Chain,
|
private val chain: Chain,
|
||||||
private val valueType: ValueContainer.ValueType,
|
private val valueType: ValueContainer.ValueType,
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import java.time.Instant
|
|||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
abstract class OnTxRedisCache<T>(
|
abstract class OnTxRedisCache<T : Any>(
|
||||||
private val redis: RedisReactiveCommands<String, ByteArray>,
|
private val redis: RedisReactiveCommands<String, ByteArray>,
|
||||||
private val chain: Chain,
|
private val chain: Chain,
|
||||||
private val valueType: CachesProto.ValueContainer.ValueType,
|
private val valueType: CachesProto.ValueContainer.ValueType,
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import java.time.Duration
|
|||||||
/**
|
/**
|
||||||
* A flux holder that reconnects to it on failure taking into account a back off strategy
|
* A flux holder that reconnects to it on failure taking into account a back off strategy
|
||||||
*/
|
*/
|
||||||
class DurableFlux<T>(
|
class DurableFlux<T : Any>(
|
||||||
private val provider: () -> Flux<T>,
|
private val provider: () -> Flux<T>,
|
||||||
private val errorBackOff: BackOff,
|
private val errorBackOff: BackOff,
|
||||||
private val log: Logger,
|
private val log: Logger,
|
||||||
@@ -55,7 +55,7 @@ class DurableFlux<T>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Builder<T> {
|
class Builder<T : Any> {
|
||||||
|
|
||||||
private var provider: (() -> Flux<T>)? = null
|
private var provider: (() -> Flux<T>)? = null
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ class DurableFlux<T>(
|
|||||||
protected var log: Logger = DurableFlux.defaultLog
|
protected var log: Logger = DurableFlux.defaultLog
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
fun <X> using(provider: () -> Flux<X>): Builder<X> {
|
fun <X : Any> using(provider: () -> Flux<X>): Builder<X> {
|
||||||
this.provider = provider as () -> Flux<T>
|
this.provider = provider as () -> Flux<T>
|
||||||
return this as Builder<X>
|
return this as Builder<X>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import reactor.core.publisher.Sinks
|
|||||||
import reactor.core.scheduler.Scheduler
|
import reactor.core.scheduler.Scheduler
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
class DynamicMergeFlux<K : Any, T>(private val scheduler: Scheduler) {
|
class DynamicMergeFlux<K : Any, T : Any>(private val scheduler: Scheduler) {
|
||||||
|
|
||||||
private val merge = Sinks.many().multicast().directBestEffort<T>()
|
private val merge = Sinks.many().multicast().directBestEffort<T>()
|
||||||
private val sources = ConcurrentHashMap<K, Disposable>()
|
private val sources = ConcurrentHashMap<K, Disposable>()
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import kotlin.concurrent.write
|
|||||||
* A flux holder that that creates it only if requested. Keeps it for the following calls, so all the following calls will
|
* A flux holder that that creates it only if requested. Keeps it for the following calls, so all the following calls will
|
||||||
* reuse it. Forgets as soon as it completes/cancelled, so it will be recreated again if needed.
|
* reuse it. Forgets as soon as it completes/cancelled, so it will be recreated again if needed.
|
||||||
*/
|
*/
|
||||||
class SharedFluxHolder<T>(
|
class SharedFluxHolder<T : Any>(
|
||||||
/**
|
/**
|
||||||
* Provider for the flux. Note that it can be called multiple times but only one is used at the same time.
|
* Provider for the flux. Note that it can be called multiple times but only one is used at the same time.
|
||||||
* I.e., if there is a few calls because of a thread-race only one is kept.
|
* I.e., if there is a few calls because of a thread-race only one is kept.
|
||||||
@@ -66,7 +66,7 @@ class SharedFluxHolder<T>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Holder<T>(
|
data class Holder<T : Any>(
|
||||||
val flux: Flux<T>,
|
val flux: Flux<T>,
|
||||||
val id: Long,
|
val id: Long,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -91,7 +91,6 @@ class AuthConfigReader : YamlConfigReader<AuthConfig>() {
|
|||||||
auth.clientCAs.add(it)
|
auth.clientCAs.add(it)
|
||||||
}
|
}
|
||||||
getList<ScalarNode>(clientNode, "cas")?.let {
|
getList<ScalarNode>(clientNode, "cas")?.let {
|
||||||
println(it)
|
|
||||||
it.value?.let { crt ->
|
it.value?.let { crt ->
|
||||||
auth.clientCAs.addAll(crt.map { v -> v.value })
|
auth.clientCAs.addAll(crt.map { v -> v.value })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ class TokensConfig(
|
|||||||
id.isNullOrBlank() -> "id"
|
id.isNullOrBlank() -> "id"
|
||||||
blockchain == null -> "blockchain"
|
blockchain == null -> "blockchain"
|
||||||
name.isNullOrBlank() -> "name"
|
name.isNullOrBlank() -> "name"
|
||||||
type == null -> type
|
type == null -> "type"
|
||||||
address.isNullOrBlank() -> "address"
|
address.isNullOrBlank() -> "address"
|
||||||
blockchain != null &&
|
blockchain != null &&
|
||||||
(blockchain!!.type == BlockchainType.ETHEREUM) &&
|
(blockchain!!.type == BlockchainType.ETHEREUM) &&
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import io.emeraldpay.dshackle.upstream.generic.ChainSpecificRegistry
|
|||||||
import io.emeraldpay.dshackle.upstream.generic.GenericMultistream
|
import io.emeraldpay.dshackle.upstream.generic.GenericMultistream
|
||||||
import org.springframework.beans.factory.annotation.Qualifier
|
import org.springframework.beans.factory.annotation.Qualifier
|
||||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory
|
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory
|
||||||
import org.springframework.cloud.sleuth.Tracer
|
|
||||||
import org.springframework.context.annotation.Bean
|
import org.springframework.context.annotation.Bean
|
||||||
import org.springframework.context.annotation.Configuration
|
import org.springframework.context.annotation.Configuration
|
||||||
import reactor.core.scheduler.Scheduler
|
import reactor.core.scheduler.Scheduler
|
||||||
@@ -26,7 +25,6 @@ open class MultistreamsConfig(val beanFactory: ConfigurableListableBeanFactory)
|
|||||||
headScheduler: Scheduler,
|
headScheduler: Scheduler,
|
||||||
@Qualifier("subScheduler")
|
@Qualifier("subScheduler")
|
||||||
subScheduler: Scheduler,
|
subScheduler: Scheduler,
|
||||||
tracer: Tracer,
|
|
||||||
multistreamEventsScheduler: Scheduler,
|
multistreamEventsScheduler: Scheduler,
|
||||||
): List<Multistream> {
|
): List<Multistream> {
|
||||||
return Chain.entries
|
return Chain.entries
|
||||||
@@ -40,7 +38,6 @@ open class MultistreamsConfig(val beanFactory: ConfigurableListableBeanFactory)
|
|||||||
cachesFactory,
|
cachesFactory,
|
||||||
headScheduler,
|
headScheduler,
|
||||||
subScheduler,
|
subScheduler,
|
||||||
tracer,
|
|
||||||
multistreamEventsScheduler,
|
multistreamEventsScheduler,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -52,7 +49,6 @@ open class MultistreamsConfig(val beanFactory: ConfigurableListableBeanFactory)
|
|||||||
cachesFactory: CachesFactory,
|
cachesFactory: CachesFactory,
|
||||||
headScheduler: Scheduler,
|
headScheduler: Scheduler,
|
||||||
subScheduler: Scheduler,
|
subScheduler: Scheduler,
|
||||||
tracer: Tracer,
|
|
||||||
multistreamEventsScheduler: Scheduler,
|
multistreamEventsScheduler: Scheduler,
|
||||||
): Multistream {
|
): Multistream {
|
||||||
val name = "multi-$chain"
|
val name = "multi-$chain"
|
||||||
@@ -65,7 +61,7 @@ open class MultistreamsConfig(val beanFactory: ConfigurableListableBeanFactory)
|
|||||||
CopyOnWriteArrayList(),
|
CopyOnWriteArrayList(),
|
||||||
caches,
|
caches,
|
||||||
headScheduler,
|
headScheduler,
|
||||||
cs.makeCachingReaderBuilder(tracer),
|
cs.makeCachingReaderBuilder(),
|
||||||
cs::localReaderBuilder,
|
cs::localReaderBuilder,
|
||||||
cs.subscriptionBuilder(subScheduler),
|
cs.subscriptionBuilder(subScheduler),
|
||||||
).also { register(it, name) }
|
).also { register(it, name) }
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
package io.emeraldpay.dshackle.config.context
|
package io.emeraldpay.dshackle.config.context
|
||||||
|
|
||||||
import io.emeraldpay.dshackle.config.MonitoringConfig
|
|
||||||
import io.micrometer.core.instrument.Metrics
|
import io.micrometer.core.instrument.Metrics
|
||||||
import io.micrometer.core.instrument.Tag
|
|
||||||
import io.micrometer.core.instrument.binder.jvm.ExecutorServiceMetrics
|
import io.micrometer.core.instrument.binder.jvm.ExecutorServiceMetrics
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.context.annotation.Bean
|
import org.springframework.context.annotation.Bean
|
||||||
import org.springframework.context.annotation.Configuration
|
import org.springframework.context.annotation.Configuration
|
||||||
|
import org.springframework.context.annotation.DependsOn
|
||||||
import org.springframework.scheduling.concurrent.CustomizableThreadFactory
|
import org.springframework.scheduling.concurrent.CustomizableThreadFactory
|
||||||
import reactor.core.scheduler.Scheduler
|
import reactor.core.scheduler.Scheduler
|
||||||
import reactor.core.scheduler.Schedulers
|
import reactor.core.scheduler.Schedulers
|
||||||
@@ -17,6 +16,7 @@ import java.util.concurrent.ThreadPoolExecutor
|
|||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
|
@DependsOn("monitoringSetup")
|
||||||
open class SchedulersConfig {
|
open class SchedulersConfig {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@@ -32,65 +32,65 @@ open class SchedulersConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
open fun rpcScheduler(monitoringConfig: MonitoringConfig): Scheduler {
|
open fun rpcScheduler(): Scheduler {
|
||||||
return makeScheduler("blockchain-rpc-scheduler", 20, monitoringConfig)
|
return makeScheduler("blockchain-rpc-scheduler", 20)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
open fun headScheduler(monitoringConfig: MonitoringConfig): Scheduler {
|
open fun headScheduler(): Scheduler {
|
||||||
return makeScheduler("head-scheduler", 4, monitoringConfig)
|
return makeScheduler("head-scheduler", 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
open fun subScheduler(monitoringConfig: MonitoringConfig): Scheduler {
|
open fun subScheduler(): Scheduler {
|
||||||
return makeScheduler("sub-scheduler", 4, monitoringConfig)
|
return makeScheduler("sub-scheduler", 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
open fun multistreamEventsScheduler(monitoringConfig: MonitoringConfig): Scheduler {
|
open fun multistreamEventsScheduler(): Scheduler {
|
||||||
return makeScheduler("events-scheduler", 4, monitoringConfig)
|
return makeScheduler("events-scheduler", 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
open fun wsConnectionResubscribeScheduler(monitoringConfig: MonitoringConfig): Scheduler {
|
open fun wsConnectionResubscribeScheduler(): Scheduler {
|
||||||
return makeScheduler("ws-connection-resubscribe-scheduler", 2, monitoringConfig)
|
return makeScheduler("ws-connection-resubscribe-scheduler", 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
open fun wsScheduler(monitoringConfig: MonitoringConfig): Scheduler {
|
open fun wsScheduler(): Scheduler {
|
||||||
return makeScheduler("ws-scheduler", 4, monitoringConfig)
|
return makeScheduler("ws-scheduler", 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
open fun headLivenessScheduler(monitoringConfig: MonitoringConfig): Scheduler {
|
open fun headLivenessScheduler(): Scheduler {
|
||||||
return makeScheduler("head-liveness-scheduler", 4, monitoringConfig)
|
return makeScheduler("head-liveness-scheduler", 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
open fun grpcChannelExecutor(monitoringConfig: MonitoringConfig): Executor {
|
open fun grpcChannelExecutor(): Executor {
|
||||||
return makePool("grpc-client-channel", 10, monitoringConfig)
|
return makePool("grpc-client-channel", 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
open fun authScheduler(monitoringConfig: MonitoringConfig): Scheduler {
|
open fun authScheduler(): Scheduler {
|
||||||
return makeScheduler("auth-scheduler", 4, monitoringConfig)
|
return makeScheduler("auth-scheduler", 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
open fun httpScheduler(monitoringConfig: MonitoringConfig): Scheduler {
|
open fun httpScheduler(): Scheduler {
|
||||||
return makeScheduler("http-scheduler", 30, monitoringConfig)
|
return makeScheduler("http-scheduler", 30)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
open fun eventsScheduler(monitoringConfig: MonitoringConfig): Scheduler {
|
open fun eventsScheduler(): Scheduler {
|
||||||
return makeScheduler("ws-events-scheduler", 30, monitoringConfig)
|
return makeScheduler("ws-events-scheduler", 30)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun makeScheduler(name: String, size: Int, monitoringConfig: MonitoringConfig): Scheduler {
|
private fun makeScheduler(name: String, size: Int): Scheduler {
|
||||||
return Schedulers.fromExecutorService(makePool(name, size, monitoringConfig))
|
return Schedulers.fromExecutorService(makePool(name, size))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun makePool(name: String, size: Int, monitoringConfig: MonitoringConfig): ExecutorService {
|
private fun makePool(name: String, size: Int): ExecutorService {
|
||||||
val cachedPool = ThreadPoolExecutor(
|
val cachedPool = ThreadPoolExecutor(
|
||||||
size,
|
size,
|
||||||
size * threadsMultiplier,
|
size * threadsMultiplier,
|
||||||
@@ -100,15 +100,10 @@ open class SchedulersConfig {
|
|||||||
CustomizableThreadFactory("$name-"),
|
CustomizableThreadFactory("$name-"),
|
||||||
)
|
)
|
||||||
|
|
||||||
return if (monitoringConfig.enableExtended) {
|
return ExecutorServiceMetrics.monitor(
|
||||||
ExecutorServiceMetrics.monitor(
|
Metrics.globalRegistry,
|
||||||
Metrics.globalRegistry,
|
cachedPool,
|
||||||
cachedPool,
|
name,
|
||||||
name,
|
)
|
||||||
Tag.of("reactor_scheduler_id", "_"),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
cachedPool
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package io.emeraldpay.dshackle.config.context
|
package io.emeraldpay.dshackle.config.context
|
||||||
|
|
||||||
|
import brave.Tracing
|
||||||
|
import brave.context.slf4j.MDCScopeDecorator
|
||||||
import brave.grpc.GrpcTracing
|
import brave.grpc.GrpcTracing
|
||||||
|
import brave.propagation.CurrentTraceContext
|
||||||
import brave.rpc.RpcTracing
|
import brave.rpc.RpcTracing
|
||||||
import brave.sampler.Sampler
|
import brave.sampler.Sampler
|
||||||
import io.grpc.ServerInterceptor
|
import io.grpc.ServerInterceptor
|
||||||
@@ -9,14 +12,28 @@ import org.springframework.context.annotation.Configuration
|
|||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
open class TraceConfiguration {
|
open class TraceConfiguration {
|
||||||
|
@Bean
|
||||||
|
open fun defaultSampler(): Sampler = Sampler.ALWAYS_SAMPLE
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
open fun braveTracing(defaultSampler: Sampler): Tracing {
|
||||||
|
val currentTraceContext =
|
||||||
|
CurrentTraceContext.Default.newBuilder()
|
||||||
|
.addScopeDecorator(MDCScopeDecorator.newBuilder().build())
|
||||||
|
.build()
|
||||||
|
|
||||||
|
return Tracing.newBuilder()
|
||||||
|
.localServiceName("grpc-server")
|
||||||
|
.currentTraceContext(currentTraceContext)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
open fun rpcTracing(tracing: Tracing): RpcTracing = RpcTracing.create(tracing)
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
open fun grpcTracing(rpcTracing: RpcTracing): GrpcTracing = GrpcTracing.create(rpcTracing)
|
open fun grpcTracing(rpcTracing: RpcTracing): GrpcTracing = GrpcTracing.create(rpcTracing)
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
open fun grpcServerBraveInterceptor(grpcTracing: GrpcTracing): ServerInterceptor =
|
open fun grpcServerBraveInterceptor(grpcTracing: GrpcTracing): ServerInterceptor = grpcTracing.newServerInterceptor()
|
||||||
grpcTracing.newServerInterceptor()
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
open fun defaultSampler(): Sampler = Sampler.ALWAYS_SAMPLE
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package io.emeraldpay.dshackle.config.hot
|
package io.emeraldpay.dshackle.config.hot
|
||||||
|
|
||||||
import io.emeraldpay.dshackle.Global
|
import io.emeraldpay.dshackle.Global
|
||||||
|
import org.apache.hc.client5.http.classic.methods.HttpGet
|
||||||
|
import org.apache.hc.client5.http.impl.classic.HttpClients
|
||||||
|
import org.apache.hc.core5.http.io.entity.EntityUtils
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.web.client.RestTemplate
|
|
||||||
import reactor.core.publisher.Flux
|
import reactor.core.publisher.Flux
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
import java.util.concurrent.atomic.AtomicReference
|
import java.util.concurrent.atomic.AtomicReference
|
||||||
@@ -17,12 +19,13 @@ class AutoReloadbleConfig<T>(
|
|||||||
private val log = LoggerFactory.getLogger(AutoReloadbleConfig::class.java)
|
private val log = LoggerFactory.getLogger(AutoReloadbleConfig::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val restTemplate = RestTemplate()
|
private val httpClient = HttpClients.createDefault()
|
||||||
private val instance = AtomicReference<T>()
|
private val instance = AtomicReference<T>()
|
||||||
|
|
||||||
fun reload() {
|
fun reload() {
|
||||||
try {
|
try {
|
||||||
val response = restTemplate.getForObject(configUrl, String::class.java)
|
val getReq = HttpGet(configUrl)
|
||||||
|
val response = httpClient.execute<String>(getReq) { resp -> EntityUtils.toString(resp.entity) }
|
||||||
if (response != null) {
|
if (response != null) {
|
||||||
instance.set(parseConfig(response))
|
instance.set(parseConfig(response))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,16 +5,16 @@ import com.fasterxml.jackson.annotation.JsonProperty
|
|||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class CompatibleVersionsRules(
|
data class CompatibleVersionsRules(
|
||||||
@JsonProperty("rules")
|
@param:JsonProperty("rules")
|
||||||
val rules: List<CompatibleVersionsRule>,
|
val rules: List<CompatibleVersionsRule>,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class CompatibleVersionsRule(
|
data class CompatibleVersionsRule(
|
||||||
@JsonProperty("client")
|
@param:JsonProperty("client")
|
||||||
val client: String,
|
val client: String,
|
||||||
@JsonProperty("blacklist")
|
@param:JsonProperty("blacklist")
|
||||||
val blacklist: List<String>?,
|
val blacklist: List<String>?,
|
||||||
@JsonProperty("whitelist")
|
@param:JsonProperty("whitelist")
|
||||||
val whitelist: List<String>?,
|
val whitelist: List<String>?,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
package io.emeraldpay.dshackle.config.spans
|
|
||||||
|
|
||||||
import brave.handler.MutableSpan
|
|
||||||
import io.emeraldpay.dshackle.commons.SPAN_ERROR
|
|
||||||
import io.emeraldpay.dshackle.commons.SPAN_NO_RESPONSE_MESSAGE
|
|
||||||
import org.springframework.beans.factory.annotation.Value
|
|
||||||
import org.springframework.stereotype.Component
|
|
||||||
import java.util.concurrent.TimeUnit.MICROSECONDS
|
|
||||||
import java.util.concurrent.TimeUnit.MILLISECONDS
|
|
||||||
|
|
||||||
interface SpanExportable {
|
|
||||||
fun isExportable(span: MutableSpan): Boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component
|
|
||||||
class ErrorSpanExportable : SpanExportable {
|
|
||||||
override fun isExportable(span: MutableSpan): Boolean = span.tags().containsKey(SPAN_ERROR)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component
|
|
||||||
class NoResponseSpanExportable : SpanExportable {
|
|
||||||
override fun isExportable(span: MutableSpan): Boolean = span.tags().containsKey(SPAN_NO_RESPONSE_MESSAGE)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component
|
|
||||||
class LongResponseSpanExportable(
|
|
||||||
@Value("\${spans.collect.long-span-threshold}")
|
|
||||||
private val longSpanThreshold: Long? = null,
|
|
||||||
) : SpanExportable {
|
|
||||||
|
|
||||||
override fun isExportable(span: MutableSpan): Boolean {
|
|
||||||
return MILLISECONDS.convert(
|
|
||||||
span.finishTimestamp() - span.startTimestamp(),
|
|
||||||
MICROSECONDS,
|
|
||||||
) >= longSpanThreshold!!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
package io.emeraldpay.dshackle.config.spans
|
|
||||||
|
|
||||||
import brave.handler.MutableSpan
|
|
||||||
import brave.handler.SpanHandler
|
|
||||||
import brave.propagation.TraceContext
|
|
||||||
import com.github.benmanes.caffeine.cache.Caffeine
|
|
||||||
import org.slf4j.LoggerFactory
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
|
|
||||||
import org.springframework.stereotype.Component
|
|
||||||
import java.time.Duration
|
|
||||||
|
|
||||||
@Component
|
|
||||||
@ConditionalOnProperty(value = ["spring.zipkin.enabled"], havingValue = "true")
|
|
||||||
class ProviderSpanHandler(
|
|
||||||
private val spanExportableList: List<SpanExportable>,
|
|
||||||
private val zipkinSpanHandler: SpanHandler,
|
|
||||||
) : SpanHandler() {
|
|
||||||
private val log = LoggerFactory.getLogger(ProviderSpanHandler::class.java)
|
|
||||||
|
|
||||||
private val spans = Caffeine
|
|
||||||
.newBuilder()
|
|
||||||
.expireAfterWrite(Duration.ofMinutes(2))
|
|
||||||
.build<String, MutableList<MutableSpan>>()
|
|
||||||
|
|
||||||
override fun end(context: TraceContext, span: MutableSpan, cause: Cause): Boolean {
|
|
||||||
if (span.traceId().length > 20 && cause == Cause.FINISHED) {
|
|
||||||
val key = span.parentId() ?: span.id()
|
|
||||||
val spanList = spans.asMap().computeIfAbsent(key) { mutableListOf() }
|
|
||||||
spanList.add(span)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
fun sendSpans(traceContext: TraceContext) {
|
|
||||||
try {
|
|
||||||
sendSpansInternal(traceContext)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
log.warn("Error while handling and sending spans - ${e.message}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun sendSpansInternal(traceContext: TraceContext) {
|
|
||||||
val spansInfo = SpansInfo()
|
|
||||||
|
|
||||||
processSpans(traceContext.spanIdString(), spansInfo)
|
|
||||||
|
|
||||||
spansInfo.spans
|
|
||||||
.map { it.parentId() }
|
|
||||||
.forEach {
|
|
||||||
if (it != null) {
|
|
||||||
spans.invalidate(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (spansInfo.exportable) {
|
|
||||||
spansInfo.spans.forEach {
|
|
||||||
zipkinSpanHandler.end(traceContext, it, Cause.FINISHED)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun processSpans(spanId: String, spansInfo: SpansInfo) {
|
|
||||||
val currentSpans: List<MutableSpan>? = spans.getIfPresent(spanId)
|
|
||||||
|
|
||||||
currentSpans?.forEach {
|
|
||||||
processSpanInfo(it, spansInfo)
|
|
||||||
if (spanId != it.id()) {
|
|
||||||
processSpans(it.id(), spansInfo)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun processSpanInfo(span: MutableSpan, spansInfo: SpansInfo) {
|
|
||||||
spansInfo.spans.add(span)
|
|
||||||
if (spanExportableList.any { it.isExportable(span) }) {
|
|
||||||
spansInfo.exportable = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private data class SpansInfo(
|
|
||||||
var exportable: Boolean = false,
|
|
||||||
val spans: MutableList<MutableSpan> = mutableListOf(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
package io.emeraldpay.dshackle.config.spans
|
|
||||||
|
|
||||||
import io.emeraldpay.dshackle.config.MainConfig
|
|
||||||
import org.apache.http.conn.ssl.SSLConnectionSocketFactory
|
|
||||||
import org.apache.http.impl.client.HttpClients
|
|
||||||
import org.bouncycastle.openssl.PEMParser
|
|
||||||
import org.springframework.cloud.sleuth.zipkin2.ZipkinRestTemplateCustomizer
|
|
||||||
import org.springframework.http.HttpRequest
|
|
||||||
import org.springframework.http.client.ClientHttpRequestExecution
|
|
||||||
import org.springframework.http.client.ClientHttpRequestInterceptor
|
|
||||||
import org.springframework.http.client.ClientHttpResponse
|
|
||||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory
|
|
||||||
import org.springframework.stereotype.Component
|
|
||||||
import org.springframework.web.client.RestTemplate
|
|
||||||
import java.io.ByteArrayOutputStream
|
|
||||||
import java.io.StringReader
|
|
||||||
import java.nio.file.Files
|
|
||||||
import java.nio.file.Paths
|
|
||||||
import java.security.KeyFactory
|
|
||||||
import java.security.KeyStore
|
|
||||||
import java.security.SecureRandom
|
|
||||||
import java.security.cert.CertificateFactory
|
|
||||||
import java.security.cert.X509Certificate
|
|
||||||
import java.security.spec.PKCS8EncodedKeySpec
|
|
||||||
import java.util.zip.GZIPOutputStream
|
|
||||||
import javax.net.ssl.KeyManagerFactory
|
|
||||||
import javax.net.ssl.SSLContext
|
|
||||||
|
|
||||||
@Component
|
|
||||||
class ZipkinSSLCustomizer(private val mainConfig: MainConfig) : ZipkinRestTemplateCustomizer {
|
|
||||||
override fun customizeTemplate(restTemplate: RestTemplate): RestTemplate {
|
|
||||||
return if (mainConfig.tls?.enabled == true) {
|
|
||||||
setupSSL(mainConfig.tls!!.certificate!!, mainConfig.tls!!.key!!)
|
|
||||||
} else {
|
|
||||||
restTemplate
|
|
||||||
}.apply {
|
|
||||||
interceptors.add(0, GZipInterceptor())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupSSL(certPath: String, privateKeyPath: String): RestTemplate {
|
|
||||||
// Load the certificate
|
|
||||||
val certificateReader = StringReader(Files.readString(Paths.get(certPath)))
|
|
||||||
val pemObject = PEMParser(certificateReader).readPemObject()
|
|
||||||
val certificate = CertificateFactory.getInstance("X.509").generateCertificate(pemObject.content.inputStream()) as X509Certificate
|
|
||||||
// Load the private key
|
|
||||||
val privateKeyReader = StringReader(Files.readString(Paths.get(privateKeyPath)))
|
|
||||||
val pemKeyPair = PEMParser(privateKeyReader).readPemObject()
|
|
||||||
val privKeySpec = PKCS8EncodedKeySpec(pemKeyPair.content)
|
|
||||||
val privateKey = KeyFactory.getInstance("RSA").generatePrivate(privKeySpec)
|
|
||||||
|
|
||||||
// Create the key store
|
|
||||||
val keyStore = KeyStore.getInstance(KeyStore.getDefaultType()).apply {
|
|
||||||
load(null, null)
|
|
||||||
setCertificateEntry("certificate", certificate)
|
|
||||||
setKeyEntry("private-key", privateKey, null, arrayOf(certificate))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the SSL context
|
|
||||||
val keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()).apply {
|
|
||||||
init(keyStore, null)
|
|
||||||
}
|
|
||||||
val sslContext = SSLContext.getInstance("TLS").apply {
|
|
||||||
init(keyManagerFactory.keyManagers, null, SecureRandom())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the HTTP client
|
|
||||||
val socketFactory = SSLConnectionSocketFactory(sslContext)
|
|
||||||
val httpClient = HttpClients.custom().setSSLSocketFactory(socketFactory).build()
|
|
||||||
|
|
||||||
// Create the request factory
|
|
||||||
val requestFactory = HttpComponentsClientHttpRequestFactory(httpClient)
|
|
||||||
|
|
||||||
// Create the RestTemplate
|
|
||||||
return RestTemplate(requestFactory)
|
|
||||||
}
|
|
||||||
|
|
||||||
private class GZipInterceptor : ClientHttpRequestInterceptor {
|
|
||||||
override fun intercept(
|
|
||||||
request: HttpRequest,
|
|
||||||
body: ByteArray,
|
|
||||||
execution: ClientHttpRequestExecution,
|
|
||||||
): ClientHttpResponse {
|
|
||||||
request.headers.add("Content-Encoding", "gzip")
|
|
||||||
val gzipped = ByteArrayOutputStream()
|
|
||||||
GZIPOutputStream(gzipped).use { compressor -> compressor.write(body) }
|
|
||||||
return execution.execute(request, gzipped.toByteArray())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -18,19 +18,18 @@ package io.emeraldpay.dshackle.monitoring
|
|||||||
import com.sun.net.httpserver.HttpServer
|
import com.sun.net.httpserver.HttpServer
|
||||||
import io.emeraldpay.dshackle.config.HealthConfig
|
import io.emeraldpay.dshackle.config.HealthConfig
|
||||||
import io.emeraldpay.dshackle.upstream.MultistreamHolder
|
import io.emeraldpay.dshackle.upstream.MultistreamHolder
|
||||||
|
import jakarta.annotation.PostConstruct
|
||||||
|
import jakarta.annotation.PreDestroy
|
||||||
|
import org.apache.hc.core5.http.HttpStatus
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
|
||||||
import org.springframework.http.HttpStatus
|
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.net.InetSocketAddress
|
import java.net.InetSocketAddress
|
||||||
import javax.annotation.PostConstruct
|
|
||||||
import javax.annotation.PreDestroy
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
class HealthCheckSetup(
|
class HealthCheckSetup(
|
||||||
@Autowired private val healthConfig: HealthConfig,
|
private val healthConfig: HealthConfig,
|
||||||
@Autowired private val multistreamHolder: MultistreamHolder,
|
private val multistreamHolder: MultistreamHolder,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@@ -63,9 +62,9 @@ class HealthCheckSetup(
|
|||||||
}
|
}
|
||||||
val ok = response.ok
|
val ok = response.ok
|
||||||
val data = response.details.joinToString("\n")
|
val data = response.details.joinToString("\n")
|
||||||
val code = if (ok) HttpStatus.OK else HttpStatus.SERVICE_UNAVAILABLE
|
val code = if (ok) HttpStatus.SC_OK else HttpStatus.SC_SERVICE_UNAVAILABLE
|
||||||
log.debug("Health check response: ${code.value()} ${code.reasonPhrase} $data")
|
log.debug("Health check response: $code $data")
|
||||||
httpExchange.sendResponseHeaders(code.value(), data.toByteArray().size.toLong())
|
httpExchange.sendResponseHeaders(code, data.toByteArray().size.toLong())
|
||||||
httpExchange.responseBody.use { os ->
|
httpExchange.responseBody.use { os ->
|
||||||
os.write(data.toByteArray())
|
os.write(data.toByteArray())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,10 +26,10 @@ import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics
|
|||||||
import io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics
|
import io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics
|
||||||
import io.micrometer.core.instrument.binder.system.ProcessorMetrics
|
import io.micrometer.core.instrument.binder.system.ProcessorMetrics
|
||||||
import io.micrometer.core.instrument.config.MeterFilter
|
import io.micrometer.core.instrument.config.MeterFilter
|
||||||
import io.micrometer.prometheus.PrometheusConfig
|
import io.micrometer.prometheusmetrics.PrometheusConfig
|
||||||
import io.micrometer.prometheus.PrometheusMeterRegistry
|
import io.micrometer.prometheusmetrics.PrometheusMeterRegistry
|
||||||
|
import jakarta.annotation.PostConstruct
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.net.InetAddress
|
import java.net.InetAddress
|
||||||
@@ -41,11 +41,10 @@ import java.util.concurrent.ThreadFactory
|
|||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
import java.util.zip.GZIPOutputStream
|
import java.util.zip.GZIPOutputStream
|
||||||
import javax.annotation.PostConstruct
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
class MonitoringSetup(
|
class MonitoringSetup(
|
||||||
@Autowired private val monitoringConfig: MonitoringConfig,
|
private val monitoringConfig: MonitoringConfig,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -23,13 +23,12 @@ import io.grpc.ServerCall
|
|||||||
import io.grpc.ServerCallHandler
|
import io.grpc.ServerCallHandler
|
||||||
import io.grpc.ServerInterceptor
|
import io.grpc.ServerInterceptor
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
class AccessHandlerGrpc(
|
class AccessHandlerGrpc(
|
||||||
@Autowired private val accessLogWriter: AccessLogWriter,
|
private val accessLogWriter: AccessLogWriter,
|
||||||
) : ServerInterceptor {
|
) : ServerInterceptor {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import io.emeraldpay.dshackle.Chain
|
|||||||
import io.emeraldpay.dshackle.config.MainConfig
|
import io.emeraldpay.dshackle.config.MainConfig
|
||||||
import io.emeraldpay.dshackle.rpc.NativeCall
|
import io.emeraldpay.dshackle.rpc.NativeCall
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import reactor.netty.http.server.HttpServerRequest
|
import reactor.netty.http.server.HttpServerRequest
|
||||||
import reactor.netty.http.websocket.WebsocketInbound
|
import reactor.netty.http.websocket.WebsocketInbound
|
||||||
@@ -20,8 +19,8 @@ import kotlin.concurrent.withLock
|
|||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
class AccessHandlerHttp(
|
class AccessHandlerHttp(
|
||||||
@Autowired private val mainConfig: MainConfig,
|
mainConfig: MainConfig,
|
||||||
@Autowired accessLogWriter: AccessLogWriter,
|
accessLogWriter: AccessLogWriter,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ package io.emeraldpay.dshackle.monitoring.accesslog
|
|||||||
|
|
||||||
import io.emeraldpay.dshackle.Global
|
import io.emeraldpay.dshackle.Global
|
||||||
import io.emeraldpay.dshackle.config.MainConfig
|
import io.emeraldpay.dshackle.config.MainConfig
|
||||||
|
import jakarta.annotation.PostConstruct
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
import org.springframework.stereotype.Repository
|
import org.springframework.stereotype.Repository
|
||||||
@@ -28,7 +29,6 @@ import java.time.Instant
|
|||||||
import java.util.concurrent.ConcurrentLinkedQueue
|
import java.util.concurrent.ConcurrentLinkedQueue
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.annotation.PostConstruct
|
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
class AccessLogWriter(
|
class AccessLogWriter(
|
||||||
|
|||||||
@@ -24,9 +24,9 @@ import io.emeraldpay.dshackle.upstream.ChainResponse
|
|||||||
import io.emeraldpay.dshackle.upstream.ethereum.rpc.RpcException
|
import io.emeraldpay.dshackle.upstream.ethereum.rpc.RpcException
|
||||||
import io.netty.buffer.ByteBuf
|
import io.netty.buffer.ByteBuf
|
||||||
import io.netty.buffer.Unpooled
|
import io.netty.buffer.Unpooled
|
||||||
|
import org.apache.hc.core5.http.HttpHeaders
|
||||||
import org.reactivestreams.Publisher
|
import org.reactivestreams.Publisher
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.http.HttpHeaders
|
|
||||||
import reactor.core.publisher.Flux
|
import reactor.core.publisher.Flux
|
||||||
import reactor.core.publisher.Mono
|
import reactor.core.publisher.Mono
|
||||||
import reactor.netty.http.server.HttpServerRequest
|
import reactor.netty.http.server.HttpServerRequest
|
||||||
|
|||||||
@@ -28,7 +28,8 @@ import io.micrometer.core.instrument.Metrics
|
|||||||
import io.micrometer.core.instrument.Timer
|
import io.micrometer.core.instrument.Timer
|
||||||
import io.netty.channel.ChannelHandler
|
import io.netty.channel.ChannelHandler
|
||||||
import io.netty.channel.ChannelHandlerContext
|
import io.netty.channel.ChannelHandlerContext
|
||||||
import io.netty.channel.nio.NioEventLoopGroup
|
import io.netty.channel.MultiThreadIoEventLoopGroup
|
||||||
|
import io.netty.channel.nio.NioIoHandler
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import reactor.netty.http.server.HttpServer
|
import reactor.netty.http.server.HttpServer
|
||||||
import reactor.netty.http.server.HttpServerRoutes
|
import reactor.netty.http.server.HttpServerRoutes
|
||||||
@@ -108,7 +109,7 @@ class ProxyServer(
|
|||||||
|
|
||||||
serverBuilder
|
serverBuilder
|
||||||
.route(this::setupRoutes)
|
.route(this::setupRoutes)
|
||||||
.runOn(NioEventLoopGroup())
|
.runOn(MultiThreadIoEventLoopGroup(NioIoHandler.newFactory()))
|
||||||
.bindNow()
|
.bindNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,12 +16,9 @@
|
|||||||
package io.emeraldpay.dshackle.quorum
|
package io.emeraldpay.dshackle.quorum
|
||||||
|
|
||||||
import io.emeraldpay.dshackle.Global
|
import io.emeraldpay.dshackle.Global
|
||||||
import io.emeraldpay.dshackle.commons.API_READER
|
|
||||||
import io.emeraldpay.dshackle.commons.SPAN_NO_RESPONSE_MESSAGE
|
|
||||||
import io.emeraldpay.dshackle.commons.SPAN_REQUEST_API_TYPE
|
import io.emeraldpay.dshackle.commons.SPAN_REQUEST_API_TYPE
|
||||||
import io.emeraldpay.dshackle.commons.SPAN_REQUEST_UPSTREAM_ID
|
import io.emeraldpay.dshackle.commons.SPAN_REQUEST_UPSTREAM_ID
|
||||||
import io.emeraldpay.dshackle.reader.RequestReader
|
import io.emeraldpay.dshackle.reader.RequestReader
|
||||||
import io.emeraldpay.dshackle.reader.SpannedReader
|
|
||||||
import io.emeraldpay.dshackle.upstream.ApiSource
|
import io.emeraldpay.dshackle.upstream.ApiSource
|
||||||
import io.emeraldpay.dshackle.upstream.ChainCallUpstreamException
|
import io.emeraldpay.dshackle.upstream.ChainCallUpstreamException
|
||||||
import io.emeraldpay.dshackle.upstream.ChainException
|
import io.emeraldpay.dshackle.upstream.ChainException
|
||||||
@@ -32,7 +29,6 @@ import io.emeraldpay.dshackle.upstream.error.UpstreamErrorHandler
|
|||||||
import io.emeraldpay.dshackle.upstream.ethereum.rpc.RpcException
|
import io.emeraldpay.dshackle.upstream.ethereum.rpc.RpcException
|
||||||
import io.emeraldpay.dshackle.upstream.signature.ResponseSigner
|
import io.emeraldpay.dshackle.upstream.signature.ResponseSigner
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.cloud.sleuth.Tracer
|
|
||||||
import reactor.core.publisher.Flux
|
import reactor.core.publisher.Flux
|
||||||
import reactor.core.publisher.Mono
|
import reactor.core.publisher.Mono
|
||||||
import reactor.util.function.Tuple2
|
import reactor.util.function.Tuple2
|
||||||
@@ -50,7 +46,6 @@ class QuorumRequestReader(
|
|||||||
private val apiControl: ApiSource,
|
private val apiControl: ApiSource,
|
||||||
private val quorum: CallQuorum,
|
private val quorum: CallQuorum,
|
||||||
signer: ResponseSigner?,
|
signer: ResponseSigner?,
|
||||||
private val tracer: Tracer,
|
|
||||||
) : RequestReader(signer) {
|
) : RequestReader(signer) {
|
||||||
private val errorHandler = UpstreamErrorHandler
|
private val errorHandler = UpstreamErrorHandler
|
||||||
|
|
||||||
@@ -58,7 +53,7 @@ class QuorumRequestReader(
|
|||||||
private val log = LoggerFactory.getLogger(QuorumRequestReader::class.java)
|
private val log = LoggerFactory.getLogger(QuorumRequestReader::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(apiControl: ApiSource, quorum: CallQuorum, tracer: Tracer) : this(apiControl, quorum, null, tracer)
|
constructor(apiControl: ApiSource, quorum: CallQuorum) : this(apiControl, quorum, null)
|
||||||
|
|
||||||
override fun attempts(): AtomicInteger = apiControl.attempts()
|
override fun attempts(): AtomicInteger = apiControl.attempts()
|
||||||
|
|
||||||
@@ -147,7 +142,7 @@ class QuorumRequestReader(
|
|||||||
SPAN_REQUEST_API_TYPE to apiReader.javaClass.name,
|
SPAN_REQUEST_API_TYPE to apiReader.javaClass.name,
|
||||||
SPAN_REQUEST_UPSTREAM_ID to api.getId(),
|
SPAN_REQUEST_UPSTREAM_ID to api.getId(),
|
||||||
)
|
)
|
||||||
return SpannedReader(apiReader, tracer, API_READER, spanParams)
|
return apiReader
|
||||||
.read(key)
|
.read(key)
|
||||||
.flatMap { response ->
|
.flatMap { response ->
|
||||||
log.trace("Received response from upstream ${api.getId()} for method ${key.method}")
|
log.trace("Received response from upstream ${api.getId()} for method ${key.method}")
|
||||||
@@ -173,7 +168,7 @@ class QuorumRequestReader(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <T> withErrorResume(api: Upstream, key: ChainRequest): Function<Mono<T>, Mono<T>> {
|
private fun <T : Any> withErrorResume(api: Upstream, key: ChainRequest): Function<Mono<T>, Mono<T>> {
|
||||||
return Function { src ->
|
return Function { src ->
|
||||||
src.onErrorResume { err ->
|
src.onErrorResume { err ->
|
||||||
errorHandler.handle(api, key, err.message)
|
errorHandler.handle(api, key, err.message)
|
||||||
@@ -232,7 +227,6 @@ class QuorumRequestReader(
|
|||||||
|
|
||||||
private fun noResponse(method: String, q: CallQuorum): Mono<Result> {
|
private fun noResponse(method: String, q: CallQuorum): Mono<Result> {
|
||||||
return apiControl.upstreamsMatchesResponse()?.run {
|
return apiControl.upstreamsMatchesResponse()?.run {
|
||||||
tracer.currentSpan()?.tag(SPAN_NO_RESPONSE_MESSAGE, getFullCause())
|
|
||||||
val cause = getCause(method) ?: return Mono.error(RpcException(1, "No response for method $method", getFullCause()))
|
val cause = getCause(method) ?: return Mono.error(RpcException(1, "No response for method $method", getFullCause()))
|
||||||
if (cause.shouldReturnNull) {
|
if (cause.shouldReturnNull) {
|
||||||
Mono.just(
|
Mono.just(
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package io.emeraldpay.dshackle.reader
|
package io.emeraldpay.dshackle.reader
|
||||||
|
|
||||||
import io.emeraldpay.dshackle.commons.BROADCAST_READER
|
|
||||||
import io.emeraldpay.dshackle.commons.SPAN_REQUEST_UPSTREAM_ID
|
|
||||||
import io.emeraldpay.dshackle.quorum.CallQuorum
|
import io.emeraldpay.dshackle.quorum.CallQuorum
|
||||||
import io.emeraldpay.dshackle.upstream.ChainException
|
import io.emeraldpay.dshackle.upstream.ChainException
|
||||||
import io.emeraldpay.dshackle.upstream.ChainRequest
|
import io.emeraldpay.dshackle.upstream.ChainRequest
|
||||||
@@ -11,7 +9,6 @@ import io.emeraldpay.dshackle.upstream.Upstream
|
|||||||
import io.emeraldpay.dshackle.upstream.error.UpstreamErrorHandler
|
import io.emeraldpay.dshackle.upstream.error.UpstreamErrorHandler
|
||||||
import io.emeraldpay.dshackle.upstream.signature.ResponseSigner
|
import io.emeraldpay.dshackle.upstream.signature.ResponseSigner
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.cloud.sleuth.Tracer
|
|
||||||
import reactor.core.publisher.Flux
|
import reactor.core.publisher.Flux
|
||||||
import reactor.core.publisher.Mono
|
import reactor.core.publisher.Mono
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
@@ -21,7 +18,6 @@ class BroadcastReader(
|
|||||||
matcher: Selector.Matcher,
|
matcher: Selector.Matcher,
|
||||||
signer: ResponseSigner?,
|
signer: ResponseSigner?,
|
||||||
private val quorum: CallQuorum,
|
private val quorum: CallQuorum,
|
||||||
private val tracer: Tracer,
|
|
||||||
) : RequestReader(signer) {
|
) : RequestReader(signer) {
|
||||||
private val errorHandler = UpstreamErrorHandler
|
private val errorHandler = UpstreamErrorHandler
|
||||||
private val internalMatcher = Selector.MultiMatcher(
|
private val internalMatcher = Selector.MultiMatcher(
|
||||||
@@ -77,12 +73,7 @@ class BroadcastReader(
|
|||||||
key: ChainRequest,
|
key: ChainRequest,
|
||||||
upstream: Upstream,
|
upstream: Upstream,
|
||||||
): Mono<BroadcastResponse> =
|
): Mono<BroadcastResponse> =
|
||||||
SpannedReader(
|
upstream.getIngressReader()
|
||||||
upstream.getIngressReader(),
|
|
||||||
tracer,
|
|
||||||
BROADCAST_READER,
|
|
||||||
mapOf(SPAN_REQUEST_UPSTREAM_ID to upstream.getId()),
|
|
||||||
)
|
|
||||||
.read(key)
|
.read(key)
|
||||||
.map { BroadcastResponse(it, upstream) }
|
.map { BroadcastResponse(it, upstream) }
|
||||||
.onErrorResume {
|
.onErrorResume {
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import reactor.core.publisher.Mono
|
|||||||
* Composition of multiple readers.
|
* Composition of multiple readers.
|
||||||
* Reader returns first value returned by any of the source readers by checking one by one until one of them returns a non-empty result.
|
* Reader returns first value returned by any of the source readers by checking one by one until one of them returns a non-empty result.
|
||||||
*/
|
*/
|
||||||
class CompoundReader<K, D> (
|
class CompoundReader<K, D : Any> (
|
||||||
private vararg val readers: Reader<K, D>,
|
private vararg val readers: Reader<K, D>,
|
||||||
) : Reader<K, D> {
|
) : Reader<K, D> {
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ package io.emeraldpay.dshackle.reader
|
|||||||
|
|
||||||
import reactor.core.publisher.Mono
|
import reactor.core.publisher.Mono
|
||||||
|
|
||||||
class EmptyReader<K, D> : Reader<K, D> {
|
class EmptyReader<K, D : Any> : Reader<K, D> {
|
||||||
|
|
||||||
override fun read(key: K): Mono<D> {
|
override fun read(key: K): Mono<D> {
|
||||||
return Mono.empty()
|
return Mono.empty()
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ package io.emeraldpay.dshackle.reader
|
|||||||
|
|
||||||
import reactor.core.publisher.Mono
|
import reactor.core.publisher.Mono
|
||||||
|
|
||||||
interface Reader<in K, D> {
|
interface Reader<in K, D : Any> {
|
||||||
|
|
||||||
fun read(key: K): Mono<D>
|
fun read(key: K): Mono<D>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import java.util.function.Function
|
|||||||
/**
|
/**
|
||||||
* Reader wrapper that maps the input key from ne value to another (ex. convert from Long to String)
|
* Reader wrapper that maps the input key from ne value to another (ex. convert from Long to String)
|
||||||
*/
|
*/
|
||||||
class RekeyingReader<K, K1, D>(
|
class RekeyingReader<K : Any, K1 : Any, D : Any>(
|
||||||
/**
|
/**
|
||||||
* Mapping between original Key and Key supported by the reader
|
* Mapping between original Key and Key supported by the reader
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import io.emeraldpay.dshackle.upstream.Upstream
|
|||||||
import io.emeraldpay.dshackle.upstream.ethereum.rpc.RpcException
|
import io.emeraldpay.dshackle.upstream.ethereum.rpc.RpcException
|
||||||
import io.emeraldpay.dshackle.upstream.signature.ResponseSigner
|
import io.emeraldpay.dshackle.upstream.signature.ResponseSigner
|
||||||
import io.emeraldpay.dshackle.upstream.stream.Chunk
|
import io.emeraldpay.dshackle.upstream.stream.Chunk
|
||||||
import org.springframework.cloud.sleuth.Tracer
|
|
||||||
import reactor.core.publisher.Flux
|
import reactor.core.publisher.Flux
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
|
|
||||||
@@ -72,10 +71,10 @@ interface RequestReaderFactory {
|
|||||||
class Default : RequestReaderFactory {
|
class Default : RequestReaderFactory {
|
||||||
override fun create(data: ReaderData): RequestReader {
|
override fun create(data: ReaderData): RequestReader {
|
||||||
if (data.quorum is MaximumValueQuorum || data.quorum is BroadcastQuorum) {
|
if (data.quorum is MaximumValueQuorum || data.quorum is BroadcastQuorum) {
|
||||||
return BroadcastReader(data.multistream.getAll(), data.upstreamFilter.matcher, data.signer, data.quorum, data.tracer)
|
return BroadcastReader(data.multistream.getAll(), data.upstreamFilter.matcher, data.signer, data.quorum)
|
||||||
}
|
}
|
||||||
val apis = data.multistream.getApiSource(data.upstreamFilter)
|
val apis = data.multistream.getApiSource(data.upstreamFilter)
|
||||||
return QuorumRequestReader(apis, data.quorum, data.signer, data.tracer)
|
return QuorumRequestReader(apis, data.quorum, data.signer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,6 +83,5 @@ interface RequestReaderFactory {
|
|||||||
val upstreamFilter: Selector.UpstreamFilter,
|
val upstreamFilter: Selector.UpstreamFilter,
|
||||||
val quorum: CallQuorum,
|
val quorum: CallQuorum,
|
||||||
val signer: ResponseSigner?,
|
val signer: ResponseSigner?,
|
||||||
val tracer: Tracer,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,58 +0,0 @@
|
|||||||
package io.emeraldpay.dshackle.reader
|
|
||||||
|
|
||||||
import io.emeraldpay.dshackle.commons.SPAN_ERROR
|
|
||||||
import io.emeraldpay.dshackle.commons.SPAN_READER_NAME
|
|
||||||
import io.emeraldpay.dshackle.commons.SPAN_READER_RESULT
|
|
||||||
import io.emeraldpay.dshackle.commons.SPAN_REQUEST_CANCELLED
|
|
||||||
import io.emeraldpay.dshackle.commons.SPAN_REQUEST_INFO
|
|
||||||
import io.emeraldpay.dshackle.commons.SPAN_STATUS_MESSAGE
|
|
||||||
import io.emeraldpay.dshackle.data.HashId
|
|
||||||
import io.emeraldpay.dshackle.upstream.ChainRequest
|
|
||||||
import org.springframework.cloud.sleuth.Tracer
|
|
||||||
import org.springframework.cloud.sleuth.instrument.reactor.ReactorSleuth
|
|
||||||
import reactor.core.publisher.Mono
|
|
||||||
import reactor.kotlin.core.publisher.switchIfEmpty
|
|
||||||
|
|
||||||
class SpannedReader<K, D>(
|
|
||||||
private val reader: Reader<K, D>,
|
|
||||||
private val tracer: Tracer,
|
|
||||||
private val name: String,
|
|
||||||
private val additionalParams: Map<String, String> = emptyMap(),
|
|
||||||
) : Reader<K, D> {
|
|
||||||
|
|
||||||
override fun read(key: K): Mono<D> {
|
|
||||||
val newSpan = tracer.nextSpan(tracer.currentSpan())
|
|
||||||
.name(reader.javaClass.name)
|
|
||||||
.tag(SPAN_READER_NAME, name)
|
|
||||||
.start()
|
|
||||||
|
|
||||||
extractInfoFromKey(key)?.let {
|
|
||||||
newSpan.tag(SPAN_REQUEST_INFO, it)
|
|
||||||
}
|
|
||||||
additionalParams.forEach { newSpan.tag(it.key, it.value) }
|
|
||||||
|
|
||||||
return reader.read(key)
|
|
||||||
.contextWrite { ReactorSleuth.putSpanInScope(tracer, it, newSpan) }
|
|
||||||
.doOnError {
|
|
||||||
newSpan.tag(SPAN_ERROR, "true")
|
|
||||||
.tag(SPAN_STATUS_MESSAGE, it.message)
|
|
||||||
.end()
|
|
||||||
}
|
|
||||||
.doOnNext { newSpan.end() }
|
|
||||||
.doOnCancel {
|
|
||||||
newSpan.tag(SPAN_STATUS_MESSAGE, SPAN_REQUEST_CANCELLED).end()
|
|
||||||
}
|
|
||||||
.switchIfEmpty {
|
|
||||||
newSpan.tag(SPAN_READER_RESULT, "empty result").end()
|
|
||||||
Mono.empty()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun extractInfoFromKey(key: K): String? {
|
|
||||||
return when (key) {
|
|
||||||
is ChainRequest -> "method: ${key.method}"
|
|
||||||
is HashId, Long -> "params: $key"
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -21,7 +21,7 @@ import java.util.function.Function
|
|||||||
/**
|
/**
|
||||||
* Reader wrapper that transforms output of the reader to a different format
|
* Reader wrapper that transforms output of the reader to a different format
|
||||||
*/
|
*/
|
||||||
class TransformingReader<K, D0, D>(
|
class TransformingReader<K, D0 : Any, D : Any>(
|
||||||
/**
|
/**
|
||||||
* Actual reader
|
* Actual reader
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -16,19 +16,16 @@
|
|||||||
*/
|
*/
|
||||||
package io.emeraldpay.dshackle.rpc
|
package io.emeraldpay.dshackle.rpc
|
||||||
|
|
||||||
import brave.Tracer
|
|
||||||
import io.emeraldpay.api.proto.BlockchainOuterClass
|
import io.emeraldpay.api.proto.BlockchainOuterClass
|
||||||
import io.emeraldpay.api.proto.Common
|
import io.emeraldpay.api.proto.Common
|
||||||
import io.emeraldpay.api.proto.ReactorBlockchainGrpc
|
import io.emeraldpay.api.proto.ReactorBlockchainGrpc
|
||||||
import io.emeraldpay.dshackle.Chain
|
import io.emeraldpay.dshackle.Chain
|
||||||
import io.emeraldpay.dshackle.ChainValue
|
import io.emeraldpay.dshackle.ChainValue
|
||||||
import io.emeraldpay.dshackle.config.spans.ProviderSpanHandler
|
|
||||||
import io.micrometer.core.instrument.Counter
|
import io.micrometer.core.instrument.Counter
|
||||||
import io.micrometer.core.instrument.Metrics
|
import io.micrometer.core.instrument.Metrics
|
||||||
import io.micrometer.core.instrument.Timer
|
import io.micrometer.core.instrument.Timer
|
||||||
import org.apache.commons.lang3.RandomStringUtils
|
import org.apache.commons.lang3.RandomStringUtils
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
|
||||||
import org.springframework.beans.factory.annotation.Qualifier
|
import org.springframework.beans.factory.annotation.Qualifier
|
||||||
import org.springframework.context.annotation.DependsOn
|
import org.springframework.context.annotation.DependsOn
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
@@ -47,11 +44,8 @@ class BlockchainRpc(
|
|||||||
private val describe: Describe,
|
private val describe: Describe,
|
||||||
private val subscribeStatus: SubscribeStatus,
|
private val subscribeStatus: SubscribeStatus,
|
||||||
private val subscribeNodeStatus: SubscribeNodeStatus,
|
private val subscribeNodeStatus: SubscribeNodeStatus,
|
||||||
@Qualifier("rpcScheduler")
|
@param:Qualifier("rpcScheduler")
|
||||||
private val scheduler: Scheduler,
|
private val scheduler: Scheduler,
|
||||||
@Autowired(required = false)
|
|
||||||
private val providerSpanHandler: ProviderSpanHandler?,
|
|
||||||
private val tracer: Tracer,
|
|
||||||
private val subscribeChainStatus: SubscribeChainStatus,
|
private val subscribeChainStatus: SubscribeChainStatus,
|
||||||
) : ReactorBlockchainGrpc.BlockchainImplBase() {
|
) : ReactorBlockchainGrpc.BlockchainImplBase() {
|
||||||
|
|
||||||
@@ -100,10 +94,6 @@ class BlockchainRpc(
|
|||||||
}
|
}
|
||||||
}.doOnError {
|
}.doOnError {
|
||||||
failMetric.increment()
|
failMetric.increment()
|
||||||
}.doFinally {
|
|
||||||
tracer.currentSpan()?.run {
|
|
||||||
providerSpanHandler?.sendSpans(this.context())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,14 +21,13 @@ import io.emeraldpay.api.proto.Common
|
|||||||
import io.emeraldpay.dshackle.Global
|
import io.emeraldpay.dshackle.Global
|
||||||
import io.emeraldpay.dshackle.upstream.Capability
|
import io.emeraldpay.dshackle.upstream.Capability
|
||||||
import io.emeraldpay.dshackle.upstream.MultistreamHolder
|
import io.emeraldpay.dshackle.upstream.MultistreamHolder
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import reactor.core.publisher.Mono
|
import reactor.core.publisher.Mono
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
class Describe(
|
class Describe(
|
||||||
@Autowired private val multistreamHolder: MultistreamHolder,
|
private val multistreamHolder: MultistreamHolder,
|
||||||
@Autowired private val subscribeStatus: SubscribeStatus,
|
private val subscribeStatus: SubscribeStatus,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun describe(requestMono: Mono<BlockchainOuterClass.DescribeRequest>): Mono<BlockchainOuterClass.DescribeResponse> {
|
fun describe(requestMono: Mono<BlockchainOuterClass.DescribeRequest>): Mono<BlockchainOuterClass.DescribeResponse> {
|
||||||
|
|||||||
@@ -25,19 +25,12 @@ import io.emeraldpay.dshackle.Chain
|
|||||||
import io.emeraldpay.dshackle.Global
|
import io.emeraldpay.dshackle.Global
|
||||||
import io.emeraldpay.dshackle.Global.Companion.nullValue
|
import io.emeraldpay.dshackle.Global.Companion.nullValue
|
||||||
import io.emeraldpay.dshackle.SilentException
|
import io.emeraldpay.dshackle.SilentException
|
||||||
import io.emeraldpay.dshackle.commons.LOCAL_READER
|
|
||||||
import io.emeraldpay.dshackle.commons.RPC_READER
|
|
||||||
import io.emeraldpay.dshackle.commons.SPAN_ERROR
|
|
||||||
import io.emeraldpay.dshackle.commons.SPAN_REQUEST_CANCELLED
|
|
||||||
import io.emeraldpay.dshackle.commons.SPAN_REQUEST_ID
|
|
||||||
import io.emeraldpay.dshackle.commons.SPAN_STATUS_MESSAGE
|
|
||||||
import io.emeraldpay.dshackle.config.MainConfig
|
import io.emeraldpay.dshackle.config.MainConfig
|
||||||
import io.emeraldpay.dshackle.quorum.CallQuorum
|
import io.emeraldpay.dshackle.quorum.CallQuorum
|
||||||
import io.emeraldpay.dshackle.quorum.NotLaggingQuorum
|
import io.emeraldpay.dshackle.quorum.NotLaggingQuorum
|
||||||
import io.emeraldpay.dshackle.reader.RequestReader
|
import io.emeraldpay.dshackle.reader.RequestReader
|
||||||
import io.emeraldpay.dshackle.reader.RequestReaderFactory
|
import io.emeraldpay.dshackle.reader.RequestReaderFactory
|
||||||
import io.emeraldpay.dshackle.reader.RequestReaderFactory.ReaderData
|
import io.emeraldpay.dshackle.reader.RequestReaderFactory.ReaderData
|
||||||
import io.emeraldpay.dshackle.reader.SpannedReader
|
|
||||||
import io.emeraldpay.dshackle.upstream.ApiSource
|
import io.emeraldpay.dshackle.upstream.ApiSource
|
||||||
import io.emeraldpay.dshackle.upstream.ChainCallError
|
import io.emeraldpay.dshackle.upstream.ChainCallError
|
||||||
import io.emeraldpay.dshackle.upstream.ChainException
|
import io.emeraldpay.dshackle.upstream.ChainException
|
||||||
@@ -61,21 +54,16 @@ import io.micrometer.core.instrument.Metrics
|
|||||||
import org.apache.commons.lang3.StringUtils
|
import org.apache.commons.lang3.StringUtils
|
||||||
import org.reactivestreams.Publisher
|
import org.reactivestreams.Publisher
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.cloud.sleuth.Span
|
|
||||||
import org.springframework.cloud.sleuth.Tracer
|
|
||||||
import org.springframework.cloud.sleuth.instrument.reactor.ReactorSleuth
|
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import reactor.core.publisher.Flux
|
import reactor.core.publisher.Flux
|
||||||
import reactor.core.publisher.Mono
|
import reactor.core.publisher.Mono
|
||||||
import reactor.kotlin.core.publisher.toMono
|
import reactor.kotlin.core.publisher.toMono
|
||||||
import reactor.util.context.Context
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
open class NativeCall(
|
open class NativeCall(
|
||||||
private val multistreamHolder: MultistreamHolder,
|
private val multistreamHolder: MultistreamHolder,
|
||||||
private val signer: ResponseSigner,
|
private val signer: ResponseSigner,
|
||||||
config: MainConfig,
|
config: MainConfig,
|
||||||
private val tracer: Tracer,
|
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val log = LoggerFactory.getLogger(NativeCall::class.java)
|
private val log = LoggerFactory.getLogger(NativeCall::class.java)
|
||||||
@@ -89,16 +77,14 @@ open class NativeCall(
|
|||||||
return nativeCallResult(requestMono)
|
return nativeCallResult(requestMono)
|
||||||
.flatMapSequential(this::processCallResult)
|
.flatMapSequential(this::processCallResult)
|
||||||
.onErrorResume(this::processException)
|
.onErrorResume(this::processException)
|
||||||
|
.contextCapture()
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun nativeCallResult(requestMono: Mono<BlockchainOuterClass.NativeCallRequest>): Flux<CallResult> {
|
open fun nativeCallResult(requestMono: Mono<BlockchainOuterClass.NativeCallRequest>): Flux<CallResult> {
|
||||||
val requestSpan = tracer.currentSpan()
|
|
||||||
return requestMono.flatMapMany(this::prepareCall)
|
return requestMono.flatMapMany(this::prepareCall)
|
||||||
.flatMap {
|
.flatMap {
|
||||||
val requestId = it.requestId
|
|
||||||
val requestCount = it.requestCount
|
|
||||||
val id = it.getContextId()
|
val id = it.getContextId()
|
||||||
val result = processCallContext(it, requestSpan)
|
val result = processCallContext(it)
|
||||||
|
|
||||||
return@flatMap result
|
return@flatMap result
|
||||||
.onErrorResume { err ->
|
.onErrorResume { err ->
|
||||||
@@ -122,12 +108,7 @@ open class NativeCall(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
completeSpan(callRes, requestCount)
|
|
||||||
}
|
}
|
||||||
.doOnCancel {
|
|
||||||
tracer.currentSpan()?.tag(SPAN_STATUS_MESSAGE, SPAN_REQUEST_CANCELLED)?.end()
|
|
||||||
}
|
|
||||||
.contextWrite { ctx -> createTracingReactorContext(ctx, requestCount, requestId, requestSpan) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,42 +159,8 @@ open class NativeCall(
|
|||||||
return builder
|
return builder
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun completeSpan(callResult: CallResult, requestCount: Int) {
|
|
||||||
val span = tracer.currentSpan()
|
|
||||||
if (callResult.isError()) {
|
|
||||||
errorSpan(span, callResult.error?.message ?: "Internal error")
|
|
||||||
}
|
|
||||||
if (requestCount > 1) {
|
|
||||||
span?.end()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun errorSpan(span: Span?, message: String) {
|
|
||||||
span?.apply {
|
|
||||||
tag(SPAN_ERROR, "true")
|
|
||||||
tag(SPAN_STATUS_MESSAGE, message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createTracingReactorContext(
|
|
||||||
ctx: Context,
|
|
||||||
requestCount: Int,
|
|
||||||
requestId: String,
|
|
||||||
requestSpan: Span?,
|
|
||||||
): Context {
|
|
||||||
if (requestCount > 1) {
|
|
||||||
val span = tracer.nextSpan(requestSpan)
|
|
||||||
.name("emerald.blockchain/nativecall")
|
|
||||||
.tag(SPAN_REQUEST_ID, requestId)
|
|
||||||
.start()
|
|
||||||
return ReactorSleuth.putSpanInScope(tracer, ctx, span)
|
|
||||||
}
|
|
||||||
return ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun processCallContext(
|
private fun processCallContext(
|
||||||
callContext: CallContext,
|
callContext: CallContext,
|
||||||
requestSpan: Span?,
|
|
||||||
): Mono<CallResult> {
|
): Mono<CallResult> {
|
||||||
return if (callContext.isValid()) {
|
return if (callContext.isValid()) {
|
||||||
run {
|
run {
|
||||||
@@ -222,9 +169,6 @@ open class NativeCall(
|
|||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
return@run Mono.error(e)
|
return@run Mono.error(e)
|
||||||
}
|
}
|
||||||
if (callContext.requestCount == 1 && callContext.requestId.isNotBlank()) {
|
|
||||||
requestSpan?.tag(SPAN_REQUEST_ID, callContext.requestId)
|
|
||||||
}
|
|
||||||
this.fetch(parsed)
|
this.fetch(parsed)
|
||||||
.doOnError { e -> log.warn("Error during native call: ${e.message}") }
|
.doOnError { e -> log.warn("Error during native call: ${e.message}") }
|
||||||
}
|
}
|
||||||
@@ -306,7 +250,6 @@ open class NativeCall(
|
|||||||
0
|
0
|
||||||
}
|
}
|
||||||
val message = it?.message ?: "Internal error"
|
val message = it?.message ?: "Internal error"
|
||||||
errorSpan(tracer.currentSpan(), message)
|
|
||||||
return BlockchainOuterClass.NativeCallReplyItem.newBuilder()
|
return BlockchainOuterClass.NativeCallReplyItem.newBuilder()
|
||||||
.setSucceed(false)
|
.setSucceed(false)
|
||||||
.setErrorMessage(message)
|
.setErrorMessage(message)
|
||||||
@@ -466,7 +409,7 @@ open class NativeCall(
|
|||||||
fun fetch(ctx: ValidCallContext<ParsedCallDetails>): Mono<CallResult> {
|
fun fetch(ctx: ValidCallContext<ParsedCallDetails>): Mono<CallResult> {
|
||||||
return ctx.upstream.getLocalReader()
|
return ctx.upstream.getLocalReader()
|
||||||
.flatMap { api ->
|
.flatMap { api ->
|
||||||
SpannedReader(api, tracer, LOCAL_READER)
|
api
|
||||||
.read(ctx.payload.toChainRequest(ctx.nonce, ctx.forwardedSelector, false, ctx.upstreamFilter))
|
.read(ctx.payload.toChainRequest(ctx.nonce, ctx.forwardedSelector, false, ctx.upstreamFilter))
|
||||||
.map {
|
.map {
|
||||||
val result = it.getResult()
|
val result = it.getResult()
|
||||||
@@ -503,7 +446,7 @@ open class NativeCall(
|
|||||||
return Mono.error(RpcException(RpcResponseError.CODE_METHOD_NOT_EXIST, "Unsupported method"))
|
return Mono.error(RpcException(RpcResponseError.CODE_METHOD_NOT_EXIST, "Unsupported method"))
|
||||||
}
|
}
|
||||||
val reader = requestReaderFactory.create(
|
val reader = requestReaderFactory.create(
|
||||||
ReaderData(ctx.upstream, ctx.upstreamFilter, ctx.callQuorum, signer, tracer),
|
ReaderData(ctx.upstream, ctx.upstreamFilter, ctx.callQuorum, signer),
|
||||||
)
|
)
|
||||||
val counter = reader.attempts()
|
val counter = reader.attempts()
|
||||||
val isRipple = ctx.upstream.getChain() in listOf(Chain.RIPPLE__MAINNET, Chain.RIPPLE__TESTNET)
|
val isRipple = ctx.upstream.getChain() in listOf(Chain.RIPPLE__MAINNET, Chain.RIPPLE__TESTNET)
|
||||||
@@ -512,7 +455,7 @@ open class NativeCall(
|
|||||||
streamRequest = false
|
streamRequest = false
|
||||||
}
|
}
|
||||||
|
|
||||||
return SpannedReader(reader, tracer, RPC_READER)
|
return reader
|
||||||
.read(ctx.payload.toChainRequest(ctx.nonce, ctx.forwardedSelector, streamRequest))
|
.read(ctx.payload.toChainRequest(ctx.nonce, ctx.forwardedSelector, streamRequest))
|
||||||
.map {
|
.map {
|
||||||
val resolvedUpstreamData = it.resolvedUpstreamData.ifEmpty {
|
val resolvedUpstreamData = it.resolvedUpstreamData.ifEmpty {
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ import io.grpc.Status
|
|||||||
import io.grpc.StatusException
|
import io.grpc.StatusException
|
||||||
import org.reactivestreams.Publisher
|
import org.reactivestreams.Publisher
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import reactor.core.publisher.Flux
|
import reactor.core.publisher.Flux
|
||||||
import reactor.core.publisher.Mono
|
import reactor.core.publisher.Mono
|
||||||
@@ -39,8 +38,8 @@ import java.util.concurrent.atomic.AtomicLong
|
|||||||
|
|
||||||
@Service
|
@Service
|
||||||
open class NativeSubscribe(
|
open class NativeSubscribe(
|
||||||
@Autowired private val multistreamHolder: MultistreamHolder,
|
private val multistreamHolder: MultistreamHolder,
|
||||||
@Autowired private val signer: ResponseSigner,
|
private val signer: ResponseSigner,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -26,14 +26,13 @@ import io.emeraldpay.dshackle.upstream.MultistreamHolder
|
|||||||
import io.emeraldpay.dshackle.upstream.lowerbound.LowerBoundData
|
import io.emeraldpay.dshackle.upstream.lowerbound.LowerBoundData
|
||||||
import io.emeraldpay.dshackle.upstream.lowerbound.LowerBoundType
|
import io.emeraldpay.dshackle.upstream.lowerbound.LowerBoundType
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import reactor.core.publisher.Flux
|
import reactor.core.publisher.Flux
|
||||||
import reactor.core.publisher.Mono
|
import reactor.core.publisher.Mono
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
class StreamHead(
|
class StreamHead(
|
||||||
@Autowired private val multistreamHolder: MultistreamHolder,
|
private val multistreamHolder: MultistreamHolder,
|
||||||
) {
|
) {
|
||||||
private val log = LoggerFactory.getLogger(StreamHead::class.java)
|
private val log = LoggerFactory.getLogger(StreamHead::class.java)
|
||||||
|
|
||||||
|
|||||||
@@ -17,9 +17,9 @@
|
|||||||
package io.emeraldpay.dshackle.upstream
|
package io.emeraldpay.dshackle.upstream
|
||||||
|
|
||||||
import io.emeraldpay.dshackle.Chain
|
import io.emeraldpay.dshackle.Chain
|
||||||
|
import jakarta.annotation.PreDestroy
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.stereotype.Component
|
import org.springframework.stereotype.Component
|
||||||
import javax.annotation.PreDestroy
|
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
open class CurrentMultistreamHolder(
|
open class CurrentMultistreamHolder(
|
||||||
|
|||||||
@@ -21,5 +21,5 @@ package io.emeraldpay.dshackle.upstream
|
|||||||
interface IngressSubscription {
|
interface IngressSubscription {
|
||||||
|
|
||||||
fun getAvailableTopics(): List<String>
|
fun getAvailableTopics(): List<String>
|
||||||
fun <T> get(topic: String, params: Any?, unsubscribeMethod: String): SubscriptionConnect<T>?
|
fun <T : Any> get(topic: String, params: Any?, unsubscribeMethod: String): SubscriptionConnect<T>?
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ open class NoIngressSubscription : IngressSubscription {
|
|||||||
return listOf()
|
return listOf()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun <T> get(topic: String, params: Any?, unsubscribeMethod: String): SubscriptionConnect<T>? {
|
override fun <T : Any> get(topic: String, params: Any?, unsubscribeMethod: String): SubscriptionConnect<T>? {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import reactor.core.publisher.Flux
|
|||||||
/**
|
/**
|
||||||
* Note that T is supposed to be serializable as JSON
|
* Note that T is supposed to be serializable as JSON
|
||||||
*/
|
*/
|
||||||
interface SubscriptionConnect<T> {
|
interface SubscriptionConnect<T : Any> {
|
||||||
|
|
||||||
fun connect(matcher: Selector.Matcher): Flux<T>
|
fun connect(matcher: Selector.Matcher): Flux<T>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ abstract class BasicUpstreamSettingsDetector(
|
|||||||
protected abstract fun clientVersion(node: JsonNode): String?
|
protected abstract fun clientVersion(node: JsonNode): String?
|
||||||
protected abstract fun clientType(node: JsonNode): String?
|
protected abstract fun clientType(node: JsonNode): String?
|
||||||
|
|
||||||
protected fun detectNodeType(): Flux<Pair<String, String>?> {
|
protected fun detectNodeType(): Flux<Pair<String, String>> {
|
||||||
val nodeTypeRequest = nodeTypeRequest()
|
val nodeTypeRequest = nodeTypeRequest()
|
||||||
return upstream
|
return upstream
|
||||||
.getIngressReader()
|
.getIngressReader()
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ enum class ValidateUpstreamSettingsResult(val priority: Int) {
|
|||||||
UPSTREAM_FATAL_SETTINGS_ERROR(2),
|
UPSTREAM_FATAL_SETTINGS_ERROR(2),
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SingleValidator<T> {
|
interface SingleValidator<T : Any> {
|
||||||
fun validate(onError: T): Mono<T>
|
fun validate(onError: T): Mono<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -153,23 +153,23 @@ class BeaconChainBlockHeaderDeserializer : JsonDeserializer<BeaconChainBlockHead
|
|||||||
}
|
}
|
||||||
|
|
||||||
private data class BeaconChainSyncing(
|
private data class BeaconChainSyncing(
|
||||||
@JsonProperty("data")
|
@param:JsonProperty("data")
|
||||||
val data: BeaconChainSyncingData,
|
val data: BeaconChainSyncingData,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
private data class BeaconChainSyncingData(
|
private data class BeaconChainSyncingData(
|
||||||
@JsonProperty("is_syncing")
|
@param:JsonProperty("is_syncing")
|
||||||
val isSyncing: Boolean,
|
val isSyncing: Boolean,
|
||||||
)
|
)
|
||||||
|
|
||||||
private data class BeaconChainPeers(
|
private data class BeaconChainPeers(
|
||||||
@JsonProperty("data")
|
@param:JsonProperty("data")
|
||||||
val data: BeaconChainPeersData,
|
val data: BeaconChainPeersData,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
private data class BeaconChainPeersData(
|
private data class BeaconChainPeersData(
|
||||||
@JsonProperty("connected")
|
@param:JsonProperty("connected")
|
||||||
val connected: String,
|
val connected: String,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ open class BitcoinReader(
|
|||||||
mempool.stop()
|
mempool.stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T> castedRead(req: ChainRequest, clazz: Class<T>): Mono<T> {
|
fun <T : Any> castedRead(req: ChainRequest, clazz: Class<T>): Mono<T> {
|
||||||
return upstreams.getDirectApi(Selector.empty).flatMap { api ->
|
return upstreams.getDirectApi(Selector.empty).flatMap { api ->
|
||||||
api.read(req)
|
api.read(req)
|
||||||
.flatMap(ChainResponse::requireResult)
|
.flatMap(ChainResponse::requireResult)
|
||||||
|
|||||||
@@ -121,49 +121,49 @@ object CosmosChainSpecific : AbstractPollChainSpecific() {
|
|||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class CosmosBlockResult(
|
data class CosmosBlockResult(
|
||||||
@JsonProperty("block_id") var blockId: CosmosBlockId,
|
@param:JsonProperty("block_id") var blockId: CosmosBlockId,
|
||||||
@JsonProperty("block") var block: CosmosBlockData,
|
@param:JsonProperty("block") var block: CosmosBlockData,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class CosmosBlockId(
|
data class CosmosBlockId(
|
||||||
@JsonProperty("hash") var hash: String,
|
@param:JsonProperty("hash") var hash: String,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class CosmosHeader(
|
data class CosmosHeader(
|
||||||
@JsonProperty("last_block_id") var lastBlockId: CosmosBlockId,
|
@param:JsonProperty("last_block_id") var lastBlockId: CosmosBlockId,
|
||||||
@JsonProperty("height") var height: String,
|
@param:JsonProperty("height") var height: String,
|
||||||
@JsonProperty("time") var time: Instant,
|
@param:JsonProperty("time") var time: Instant,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class CosmosStatus(
|
data class CosmosStatus(
|
||||||
@JsonProperty("node_info") var nodeInfo: CosmosNodeInfo,
|
@param:JsonProperty("node_info") var nodeInfo: CosmosNodeInfo,
|
||||||
@JsonProperty("sync_info") var syncInfo: CosmosSyncInfo,
|
@param:JsonProperty("sync_info") var syncInfo: CosmosSyncInfo,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class CosmosNodeInfo(
|
data class CosmosNodeInfo(
|
||||||
@JsonProperty("version") var version: String,
|
@param:JsonProperty("version") var version: String,
|
||||||
@JsonProperty("network") var network: String,
|
@param:JsonProperty("network") var network: String,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class CosmosSyncInfo(
|
data class CosmosSyncInfo(
|
||||||
@JsonProperty("earliest_block_height") var earliestBlockHeight: String,
|
@param:JsonProperty("earliest_block_height") var earliestBlockHeight: String,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class CosmosBlockEvent(
|
data class CosmosBlockEvent(
|
||||||
@JsonProperty("data") var data: CosmosBlockEventData,
|
@param:JsonProperty("data") var data: CosmosBlockEventData,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class CosmosBlockEventData(
|
data class CosmosBlockEventData(
|
||||||
@JsonProperty("value") var value: CosmosBlockData,
|
@param:JsonProperty("value") var value: CosmosBlockData,
|
||||||
)
|
)
|
||||||
|
|
||||||
data class CosmosBlockData(
|
data class CosmosBlockData(
|
||||||
@JsonProperty("header") var header: CosmosHeader,
|
@param:JsonProperty("header") var header: CosmosHeader,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -17,11 +17,6 @@ package io.emeraldpay.dshackle.upstream.ethereum
|
|||||||
|
|
||||||
import io.emeraldpay.dshackle.cache.Caches
|
import io.emeraldpay.dshackle.cache.Caches
|
||||||
import io.emeraldpay.dshackle.cache.CurrentBlockCache
|
import io.emeraldpay.dshackle.cache.CurrentBlockCache
|
||||||
import io.emeraldpay.dshackle.commons.CACHE_BLOCK_BY_HASH_READER
|
|
||||||
import io.emeraldpay.dshackle.commons.CACHE_BLOCK_BY_HEIGHT_READER
|
|
||||||
import io.emeraldpay.dshackle.commons.CACHE_RECEIPTS_READER
|
|
||||||
import io.emeraldpay.dshackle.commons.CACHE_TX_BY_HASH_READER
|
|
||||||
import io.emeraldpay.dshackle.commons.DIRECT_QUORUM_RPC_READER
|
|
||||||
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 io.emeraldpay.dshackle.data.TxContainer
|
import io.emeraldpay.dshackle.data.TxContainer
|
||||||
@@ -29,7 +24,6 @@ import io.emeraldpay.dshackle.data.TxId
|
|||||||
import io.emeraldpay.dshackle.reader.CompoundReader
|
import io.emeraldpay.dshackle.reader.CompoundReader
|
||||||
import io.emeraldpay.dshackle.reader.Reader
|
import io.emeraldpay.dshackle.reader.Reader
|
||||||
import io.emeraldpay.dshackle.reader.RekeyingReader
|
import io.emeraldpay.dshackle.reader.RekeyingReader
|
||||||
import io.emeraldpay.dshackle.reader.SpannedReader
|
|
||||||
import io.emeraldpay.dshackle.upstream.CachingReader
|
import io.emeraldpay.dshackle.upstream.CachingReader
|
||||||
import io.emeraldpay.dshackle.upstream.Multistream
|
import io.emeraldpay.dshackle.upstream.Multistream
|
||||||
import io.emeraldpay.dshackle.upstream.Selector
|
import io.emeraldpay.dshackle.upstream.Selector
|
||||||
@@ -43,7 +37,6 @@ import io.emeraldpay.dshackle.upstream.ethereum.domain.Wei
|
|||||||
import io.emeraldpay.dshackle.upstream.ethereum.json.TransactionLogJson
|
import io.emeraldpay.dshackle.upstream.ethereum.json.TransactionLogJson
|
||||||
import io.emeraldpay.dshackle.upstream.finalization.FinalizationType
|
import io.emeraldpay.dshackle.upstream.finalization.FinalizationType
|
||||||
import org.apache.commons.collections4.Factory
|
import org.apache.commons.collections4.Factory
|
||||||
import org.springframework.cloud.sleuth.Tracer
|
|
||||||
import reactor.core.publisher.Mono
|
import reactor.core.publisher.Mono
|
||||||
import java.util.function.Function
|
import java.util.function.Function
|
||||||
|
|
||||||
@@ -54,29 +47,28 @@ open class EthereumCachingReader(
|
|||||||
private val up: Multistream,
|
private val up: Multistream,
|
||||||
private val caches: Caches,
|
private val caches: Caches,
|
||||||
callMethodsFactory: Factory<CallMethods>,
|
callMethodsFactory: Factory<CallMethods>,
|
||||||
private val tracer: Tracer,
|
|
||||||
) : CachingReader {
|
) : CachingReader {
|
||||||
|
|
||||||
private val balanceCache = CurrentBlockCache<Address, Wei>()
|
private val balanceCache = CurrentBlockCache<Address, Wei>()
|
||||||
private val directReader = EthereumDirectReader(up, caches, balanceCache, callMethodsFactory, tracer)
|
private val directReader = EthereumDirectReader(up, caches, balanceCache, callMethodsFactory)
|
||||||
|
|
||||||
open fun blockByFinalization(): Reader<FinalizationType, Result<BlockContainer>> {
|
open fun blockByFinalization(): Reader<FinalizationType, Result<BlockContainer>> {
|
||||||
return SpannedReader(directReader.blockByFinalizationReader, tracer, DIRECT_QUORUM_RPC_READER)
|
return directReader.blockByFinalizationReader
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun blocksByIdAsCont(upstreamFilter: Selector.UpstreamFilter): Reader<BlockId, Result<BlockContainer>> {
|
open fun blocksByIdAsCont(upstreamFilter: Selector.UpstreamFilter): Reader<BlockId, Result<BlockContainer>> {
|
||||||
val idToBlockHash = Function<BlockId, Request<BlockHash>> { id -> Request(BlockHash.from(id.value), upstreamFilter) }
|
val idToBlockHash = Function<BlockId, Request<BlockHash>> { id -> Request(BlockHash.from(id.value), upstreamFilter) }
|
||||||
return CompoundReader(
|
return CompoundReader(
|
||||||
SpannedReader(CacheWithUpstreamIdReader(caches.getBlocksByHash()), tracer, CACHE_BLOCK_BY_HASH_READER),
|
CacheWithUpstreamIdReader(caches.getBlocksByHash()),
|
||||||
SpannedReader(RekeyingReader(idToBlockHash, directReader.blockReader), tracer, DIRECT_QUORUM_RPC_READER),
|
RekeyingReader(idToBlockHash, directReader.blockReader),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun blocksByHeightAsCont(upstreamFilter: Selector.UpstreamFilter): Reader<Long, Result<BlockContainer>> {
|
open fun blocksByHeightAsCont(upstreamFilter: Selector.UpstreamFilter): Reader<Long, Result<BlockContainer>> {
|
||||||
val numToRequest = Function<Long, Request<Long>> { num -> Request(num, upstreamFilter) }
|
val numToRequest = Function<Long, Request<Long>> { num -> Request(num, upstreamFilter) }
|
||||||
return CompoundReader(
|
return CompoundReader(
|
||||||
SpannedReader(CacheWithUpstreamIdReader(caches.getBlocksByHeight()), tracer, CACHE_BLOCK_BY_HEIGHT_READER),
|
CacheWithUpstreamIdReader(caches.getBlocksByHeight()),
|
||||||
SpannedReader(RekeyingReader(numToRequest, directReader.blockByHeightReader), tracer, DIRECT_QUORUM_RPC_READER),
|
RekeyingReader(numToRequest, directReader.blockByHeightReader),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,8 +79,8 @@ open class EthereumCachingReader(
|
|||||||
open fun txByHashAsCont(upstreamFilter: Selector.UpstreamFilter): Reader<TxId, Result<TxContainer>> {
|
open fun txByHashAsCont(upstreamFilter: Selector.UpstreamFilter): Reader<TxId, Result<TxContainer>> {
|
||||||
val idToTxHash = Function<TxId, Request<TransactionId>> { id -> Request(TransactionId.from(id.value), upstreamFilter) }
|
val idToTxHash = Function<TxId, Request<TransactionId>> { id -> Request(TransactionId.from(id.value), upstreamFilter) }
|
||||||
return CompoundReader(
|
return CompoundReader(
|
||||||
CacheWithUpstreamIdReader(SpannedReader(caches.getTxByHash(), tracer, CACHE_TX_BY_HASH_READER)),
|
CacheWithUpstreamIdReader(caches.getTxByHash()),
|
||||||
SpannedReader(RekeyingReader(idToTxHash, directReader.txReader), tracer, DIRECT_QUORUM_RPC_READER),
|
RekeyingReader(idToTxHash, directReader.txReader),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,8 +98,8 @@ open class EthereumCachingReader(
|
|||||||
directReader.receiptReader,
|
directReader.receiptReader,
|
||||||
)
|
)
|
||||||
return CompoundReader(
|
return CompoundReader(
|
||||||
CacheWithUpstreamIdReader(SpannedReader(caches.getReceipts(), tracer, CACHE_RECEIPTS_READER)),
|
CacheWithUpstreamIdReader(caches.getReceipts()),
|
||||||
SpannedReader(requested, tracer, DIRECT_QUORUM_RPC_READER),
|
requested,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,7 +118,7 @@ open class EthereumCachingReader(
|
|||||||
override fun stop() {
|
override fun stop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private class CacheWithUpstreamIdReader<K, D>(
|
private class CacheWithUpstreamIdReader<K, D : Any>(
|
||||||
private val reader: Reader<K, D>,
|
private val reader: Reader<K, D>,
|
||||||
) : Reader<K, Result<D>> {
|
) : Reader<K, Result<D>> {
|
||||||
override fun read(key: K): Mono<Result<D>> {
|
override fun read(key: K): Mono<Result<D>> {
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ import io.emeraldpay.dshackle.upstream.lowerbound.LowerBoundService
|
|||||||
import io.emeraldpay.dshackle.upstream.rpcclient.ListParams
|
import io.emeraldpay.dshackle.upstream.rpcclient.ListParams
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.cloud.sleuth.Tracer
|
|
||||||
import reactor.core.publisher.Mono
|
import reactor.core.publisher.Mono
|
||||||
import reactor.core.scheduler.Scheduler
|
import reactor.core.scheduler.Scheduler
|
||||||
import java.math.BigInteger
|
import java.math.BigInteger
|
||||||
@@ -89,8 +88,8 @@ object EthereumChainSpecific : AbstractPollChainSpecific() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun makeCachingReaderBuilder(tracer: Tracer): CachingReaderBuilder {
|
override fun makeCachingReaderBuilder(): CachingReaderBuilder {
|
||||||
return { ms, caches, methodsFactory -> EthereumCachingReader(ms, caches, methodsFactory, tracer) }
|
return { ms, caches, methodsFactory -> EthereumCachingReader(ms, caches, methodsFactory) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun upstreamValidators(
|
override fun upstreamValidators(
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ import io.emeraldpay.dshackle.upstream.rpcclient.ListParams
|
|||||||
import org.apache.commons.collections4.Factory
|
import org.apache.commons.collections4.Factory
|
||||||
import org.apache.commons.lang3.exception.ExceptionUtils
|
import org.apache.commons.lang3.exception.ExceptionUtils
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.cloud.sleuth.Tracer
|
|
||||||
import reactor.core.publisher.Mono
|
import reactor.core.publisher.Mono
|
||||||
import reactor.util.retry.Retry
|
import reactor.util.retry.Retry
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
@@ -51,7 +50,6 @@ class EthereumDirectReader(
|
|||||||
private val caches: Caches,
|
private val caches: Caches,
|
||||||
private val balanceCache: CurrentBlockCache<Address, Wei>,
|
private val balanceCache: CurrentBlockCache<Address, Wei>,
|
||||||
private val callMethodsFactory: Factory<CallMethods>,
|
private val callMethodsFactory: Factory<CallMethods>,
|
||||||
private val tracer: Tracer,
|
|
||||||
) {
|
) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@@ -257,7 +255,6 @@ class EthereumDirectReader(
|
|||||||
Selector.UpstreamFilter(sort, matcher),
|
Selector.UpstreamFilter(sort, matcher),
|
||||||
callMethodsFactory.create().createQuorumFor(request.method),
|
callMethodsFactory.create().createQuorumFor(request.method),
|
||||||
null,
|
null,
|
||||||
tracer,
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}.flatMap {
|
}.flatMap {
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ class EthereumUpstreamSettingsDetector(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun detectFlashBlocks(): Mono<Pair<String, String>>? {
|
private fun detectFlashBlocks(): Mono<Pair<String, String>> {
|
||||||
return upstream.getIngressReader().read(
|
return upstream.getIngressReader().read(
|
||||||
ChainRequest(
|
ChainRequest(
|
||||||
"eth_getBlockByNumber",
|
"eth_getBlockByNumber",
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class EthereumWsIngressSubscription(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun <T> get(topic: String, params: Any?, unsubscribeMethod: String): SubscriptionConnect<T>? {
|
override fun <T : Any> get(topic: String, params: Any?, unsubscribeMethod: String): SubscriptionConnect<T>? {
|
||||||
if (topic == EthereumEgressSubscription.METHOD_PENDING_TXES) {
|
if (topic == EthereumEgressSubscription.METHOD_PENDING_TXES) {
|
||||||
return pendingTxes as SubscriptionConnect<T>
|
return pendingTxes as SubscriptionConnect<T>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ import io.emeraldpay.dshackle.upstream.calls.CallSelector
|
|||||||
import io.emeraldpay.dshackle.upstream.ethereum.WsSubscriptions
|
import io.emeraldpay.dshackle.upstream.ethereum.WsSubscriptions
|
||||||
import io.emeraldpay.dshackle.upstream.finalization.FinalizationDetector
|
import io.emeraldpay.dshackle.upstream.finalization.FinalizationDetector
|
||||||
import io.emeraldpay.dshackle.upstream.finalization.NoopFinalizationDetector
|
import io.emeraldpay.dshackle.upstream.finalization.NoopFinalizationDetector
|
||||||
import org.springframework.cloud.sleuth.Tracer
|
|
||||||
import reactor.core.publisher.Mono
|
import reactor.core.publisher.Mono
|
||||||
import reactor.core.scheduler.Scheduler
|
import reactor.core.scheduler.Scheduler
|
||||||
import java.util.function.Supplier
|
import java.util.function.Supplier
|
||||||
@@ -48,7 +47,7 @@ abstract class AbstractChainSpecific : ChainSpecific {
|
|||||||
return NoopFinalizationDetector()
|
return NoopFinalizationDetector()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun makeCachingReaderBuilder(tracer: Tracer): CachingReaderBuilder {
|
override fun makeCachingReaderBuilder(): CachingReaderBuilder {
|
||||||
return { _, _, _ -> NoopCachingReader }
|
return { _, _, _ -> NoopCachingReader }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ import io.emeraldpay.dshackle.upstream.solana.SolanaChainSpecific
|
|||||||
import io.emeraldpay.dshackle.upstream.starknet.StarknetChainSpecific
|
import io.emeraldpay.dshackle.upstream.starknet.StarknetChainSpecific
|
||||||
import io.emeraldpay.dshackle.upstream.ton.TonHttpSpecific
|
import io.emeraldpay.dshackle.upstream.ton.TonHttpSpecific
|
||||||
import org.apache.commons.collections4.Factory
|
import org.apache.commons.collections4.Factory
|
||||||
import org.springframework.cloud.sleuth.Tracer
|
|
||||||
import reactor.core.publisher.Mono
|
import reactor.core.publisher.Mono
|
||||||
import reactor.core.scheduler.Scheduler
|
import reactor.core.scheduler.Scheduler
|
||||||
import java.util.function.Supplier
|
import java.util.function.Supplier
|
||||||
@@ -77,7 +76,7 @@ interface ChainSpecific {
|
|||||||
|
|
||||||
fun subscriptionBuilder(headScheduler: Scheduler): (Multistream) -> EgressSubscription
|
fun subscriptionBuilder(headScheduler: Scheduler): (Multistream) -> EgressSubscription
|
||||||
|
|
||||||
fun makeCachingReaderBuilder(tracer: Tracer): CachingReaderBuilder
|
fun makeCachingReaderBuilder(): CachingReaderBuilder
|
||||||
|
|
||||||
fun validator(
|
fun validator(
|
||||||
chain: Chain,
|
chain: Chain,
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ class GenericIngressSubscription(
|
|||||||
private val holders = ConcurrentHashMap<Pair<String, Any?>, SubscriptionConnect<out Any>>()
|
private val holders = ConcurrentHashMap<Pair<String, Any?>, SubscriptionConnect<out Any>>()
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun <T> get(topic: String, params: Any?, unsubscribeMethod: String): SubscriptionConnect<T> {
|
override fun <T : Any> get(topic: String, params: Any?, unsubscribeMethod: String): SubscriptionConnect<T> {
|
||||||
return holders.computeIfAbsent(topic to params) { key ->
|
return holders.computeIfAbsent(topic to params) { key ->
|
||||||
GenericSubscriptionConnect(
|
GenericSubscriptionConnect(
|
||||||
chain,
|
chain,
|
||||||
@@ -58,7 +58,7 @@ class GenericSubscriptionConnect(
|
|||||||
.flatMapMany { it.t2 }
|
.flatMapMany { it.t2 }
|
||||||
.timeout(
|
.timeout(
|
||||||
Duration.ofSeconds(85),
|
Duration.ofSeconds(85),
|
||||||
Mono.empty<ByteArray?>().doOnEach {
|
Mono.empty<ByteArray>().doOnEach {
|
||||||
log.warn("Timeout during subscription to $topic after 85 seconds")
|
log.warn("Timeout during subscription to $topic after 85 seconds")
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -22,11 +22,11 @@ class GrpcUpstreamCreator(
|
|||||||
private val authorizationConfig: AuthorizationConfig,
|
private val authorizationConfig: AuthorizationConfig,
|
||||||
private val compressionConfig: CompressionConfig,
|
private val compressionConfig: CompressionConfig,
|
||||||
private val fileResolver: FileResolver,
|
private val fileResolver: FileResolver,
|
||||||
@Qualifier("grpcChannelExecutor")
|
@param:Qualifier("grpcChannelExecutor")
|
||||||
private val channelExecutor: Executor,
|
private val channelExecutor: Executor,
|
||||||
private val grpcTracing: GrpcTracing,
|
@param:Qualifier("headScheduler")
|
||||||
@Qualifier("headScheduler")
|
|
||||||
private val headScheduler: Scheduler,
|
private val headScheduler: Scheduler,
|
||||||
|
private val grpcTracing: GrpcTracing,
|
||||||
private val grpcAuthContext: GrpcAuthContext,
|
private val grpcAuthContext: GrpcAuthContext,
|
||||||
) {
|
) {
|
||||||
@Value("\${spring.application.max-metadata-size}")
|
@Value("\${spring.application.max-metadata-size}")
|
||||||
|
|||||||
@@ -107,8 +107,8 @@ object KadenaChainSpecific : AbstractPollChainSpecific() {
|
|||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class KadenaHeader(
|
data class KadenaHeader(
|
||||||
@JsonProperty("height") var height: Long,
|
@param:JsonProperty("height") var height: Long,
|
||||||
@JsonProperty("weight") var weight: String,
|
@param:JsonProperty("weight") var weight: String,
|
||||||
@JsonProperty("instance") var instance: String,
|
@param:JsonProperty("instance") var instance: String,
|
||||||
@JsonProperty("id") var id: String,
|
@param:JsonProperty("id") var id: String,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ class KadenaUpstreamSettingsDetector(
|
|||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class KadenaHeader(
|
data class KadenaHeader(
|
||||||
@JsonProperty("instance") var instance: String,
|
@param:JsonProperty("instance") var instance: String,
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun nodeTypeRequest(): NodeTypeRequest = NodeTypeRequest(clientVersionRequest())
|
override fun nodeTypeRequest(): NodeTypeRequest = NodeTypeRequest(clientVersionRequest())
|
||||||
|
|||||||
@@ -119,26 +119,26 @@ object NearChainSpecific : AbstractPollChainSpecific() {
|
|||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class NearBlock(
|
data class NearBlock(
|
||||||
@JsonProperty("header") var header: NearHeader,
|
@param:JsonProperty("header") var header: NearHeader,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class NearHeader(
|
data class NearHeader(
|
||||||
@JsonProperty("height") var height: Long,
|
@param:JsonProperty("height") var height: Long,
|
||||||
@JsonProperty("hash") var hash: String,
|
@param:JsonProperty("hash") var hash: String,
|
||||||
@JsonProperty("prev_hash") var prevHash: String,
|
@param:JsonProperty("prev_hash") var prevHash: String,
|
||||||
@JsonProperty("timestamp") var timestamp: Long,
|
@param:JsonProperty("timestamp") var timestamp: Long,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class NearStatus(
|
data class NearStatus(
|
||||||
@JsonProperty("chain_id") var chainId: String,
|
@param:JsonProperty("chain_id") var chainId: String,
|
||||||
@JsonProperty("sync_info") var syncInfo: NearSync,
|
@param:JsonProperty("sync_info") var syncInfo: NearSync,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class NearSync(
|
data class NearSync(
|
||||||
@JsonProperty("syncing") var syncing: Boolean,
|
@param:JsonProperty("syncing") var syncing: Boolean,
|
||||||
@JsonProperty("earliest_block_height") var earliestHeight: Long,
|
@param:JsonProperty("earliest_block_height") var earliestHeight: Long,
|
||||||
@JsonProperty("earliest_block_time") var earliestBlockTime: Instant,
|
@param:JsonProperty("earliest_block_time") var earliestBlockTime: Instant,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -32,13 +32,13 @@ class NearUpstreamSettingsDetector(
|
|||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
private data class NearVersionResponse(
|
private data class NearVersionResponse(
|
||||||
@JsonProperty("version")
|
@param:JsonProperty("version")
|
||||||
val nearVersion: NearVersion,
|
val nearVersion: NearVersion,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
private data class NearVersion(
|
private data class NearVersion(
|
||||||
@JsonProperty("version")
|
@param:JsonProperty("version")
|
||||||
val version: String,
|
val version: String,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -158,30 +158,30 @@ object PolkadotChainSpecific : AbstractPollChainSpecific() {
|
|||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class PolkadotBlockResponse(
|
data class PolkadotBlockResponse(
|
||||||
@JsonProperty("block") var block: PolkadotBlock,
|
@param:JsonProperty("block") var block: PolkadotBlock,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class PolkadotBlock(
|
data class PolkadotBlock(
|
||||||
@JsonProperty("header") var header: PolkadotHeader,
|
@param:JsonProperty("header") var header: PolkadotHeader,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class PolkadotHeader(
|
data class PolkadotHeader(
|
||||||
@JsonProperty("parentHash") var parentHash: String,
|
@param:JsonProperty("parentHash") var parentHash: String,
|
||||||
@JsonProperty("number") var number: String,
|
@param:JsonProperty("number") var number: String,
|
||||||
@JsonProperty("stateRoot") var stateRoot: String,
|
@param:JsonProperty("stateRoot") var stateRoot: String,
|
||||||
@JsonProperty("extrinsicsRoot") var extrinsicsRoot: String,
|
@param:JsonProperty("extrinsicsRoot") var extrinsicsRoot: String,
|
||||||
@JsonProperty("digest") var digest: PolkadotDigest,
|
@param:JsonProperty("digest") var digest: PolkadotDigest,
|
||||||
)
|
)
|
||||||
|
|
||||||
data class PolkadotDigest(
|
data class PolkadotDigest(
|
||||||
@JsonProperty("logs") var logs: List<String>,
|
@param:JsonProperty("logs") var logs: List<String>,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class PolkadotHealth(
|
data class PolkadotHealth(
|
||||||
@JsonProperty("peers") var peers: Long,
|
@param:JsonProperty("peers") var peers: Long,
|
||||||
@JsonProperty("isSyncing") var isSyncing: Boolean,
|
@param:JsonProperty("isSyncing") var isSyncing: Boolean,
|
||||||
@JsonProperty("shouldHavePeers") var shouldHavePeers: Boolean,
|
@param:JsonProperty("shouldHavePeers") var shouldHavePeers: Boolean,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package io.emeraldpay.dshackle.upstream.ripple
|
|||||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
import com.fasterxml.jackson.databind.JsonNode
|
import com.fasterxml.jackson.databind.JsonNode
|
||||||
import com.fasterxml.jackson.module.kotlin.readValue
|
|
||||||
import io.emeraldpay.dshackle.Chain
|
import io.emeraldpay.dshackle.Chain
|
||||||
import io.emeraldpay.dshackle.Global
|
import io.emeraldpay.dshackle.Global
|
||||||
import io.emeraldpay.dshackle.config.ChainsConfig.ChainConfig
|
import io.emeraldpay.dshackle.config.ChainsConfig.ChainConfig
|
||||||
@@ -181,124 +180,124 @@ class RippleUpstreamSettingsDetector(val upstream: Upstream) : BasicUpstreamSett
|
|||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class RippleInfoWrapper(
|
data class RippleInfoWrapper(
|
||||||
@JsonProperty("info") var info: RippleInfo,
|
@param:JsonProperty("info") var info: RippleInfo,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class RippleInfo(
|
data class RippleInfo(
|
||||||
@JsonProperty("clio_version") var clio: String?,
|
@param:JsonProperty("clio_version") var clio: String?,
|
||||||
@JsonProperty("build_version") var buildVersion: String?,
|
@param:JsonProperty("build_version") var buildVersion: String?,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class RippleBlock(
|
data class RippleBlock(
|
||||||
@JsonProperty("closed") var closed: RippleClosed,
|
@param:JsonProperty("closed") var closed: RippleClosed,
|
||||||
@JsonProperty("open") var open: RippleOpen?,
|
@param:JsonProperty("open") var open: RippleOpen?,
|
||||||
@JsonProperty("status") var status: String?,
|
@param:JsonProperty("status") var status: String?,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class RippleClosed(
|
data class RippleClosed(
|
||||||
@JsonProperty("ledger") var ledger: RippleClosedLedger,
|
@param:JsonProperty("ledger") var ledger: RippleClosedLedger,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class RippleOpen(
|
data class RippleOpen(
|
||||||
@JsonProperty("ledger") var ledger: RippleOpenLedger,
|
@param:JsonProperty("ledger") var ledger: RippleOpenLedger,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class RippleClosedLedger(
|
data class RippleClosedLedger(
|
||||||
@JsonProperty("account_hash") var accountHash: String,
|
@param:JsonProperty("account_hash") var accountHash: String,
|
||||||
@JsonProperty("close_flags") var closeFlags: Short,
|
@param:JsonProperty("close_flags") var closeFlags: Short,
|
||||||
@JsonProperty("close_time") var closeTime: Long,
|
@param:JsonProperty("close_time") var closeTime: Long,
|
||||||
@JsonProperty("close_time_human") var closeTimeHuman: String,
|
@param:JsonProperty("close_time_human") var closeTimeHuman: String,
|
||||||
@JsonProperty("close_time_iso") var closeTimeIso: String,
|
@param:JsonProperty("close_time_iso") var closeTimeIso: String,
|
||||||
@JsonProperty("close_time_resolution") var closeTimeResolution: Short,
|
@param:JsonProperty("close_time_resolution") var closeTimeResolution: Short,
|
||||||
@JsonProperty("closed") var closed: Boolean,
|
@param:JsonProperty("closed") var closed: Boolean,
|
||||||
@JsonProperty("ledger_hash") var ledgerHash: String,
|
@param:JsonProperty("ledger_hash") var ledgerHash: String,
|
||||||
@JsonProperty("ledger_index") var ledgerIndex: String,
|
@param:JsonProperty("ledger_index") var ledgerIndex: String,
|
||||||
@JsonProperty("parent_close_time") var parentCloseTime: Long,
|
@param:JsonProperty("parent_close_time") var parentCloseTime: Long,
|
||||||
@JsonProperty("parent_hash") var parentHash: String,
|
@param:JsonProperty("parent_hash") var parentHash: String,
|
||||||
@JsonProperty("total_coins") var totalCoins: String,
|
@param:JsonProperty("total_coins") var totalCoins: String,
|
||||||
@JsonProperty("transaction_hash") var transactionHash: String,
|
@param:JsonProperty("transaction_hash") var transactionHash: String,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class RippleOpenLedger(
|
data class RippleOpenLedger(
|
||||||
@JsonProperty("closed") var closed: Boolean,
|
@param:JsonProperty("closed") var closed: Boolean,
|
||||||
@JsonProperty("ledger_index") var ledgerIndex: String,
|
@param:JsonProperty("ledger_index") var ledgerIndex: String,
|
||||||
@JsonProperty("parent_hash") var parentHash: String,
|
@param:JsonProperty("parent_hash") var parentHash: String,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class RippleState(
|
data class RippleState(
|
||||||
@JsonProperty("state") var state: RippleServerState,
|
@param:JsonProperty("state") var state: RippleServerState,
|
||||||
@JsonProperty("status") var status: String? = null,
|
@param:JsonProperty("status") var status: String? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class RippleServerState(
|
data class RippleServerState(
|
||||||
@JsonProperty("build_version") val buildVersion: String,
|
@param:JsonProperty("build_version") val buildVersion: String,
|
||||||
@JsonProperty("complete_ledgers") val completeLedgers: String,
|
@param:JsonProperty("complete_ledgers") val completeLedgers: String,
|
||||||
@JsonProperty("initial_sync_duration_us") val initialSyncDurationUs: String?,
|
@param:JsonProperty("initial_sync_duration_us") val initialSyncDurationUs: String?,
|
||||||
@JsonProperty("io_latency_ms") val ioLatencyMs: Int,
|
@param:JsonProperty("io_latency_ms") val ioLatencyMs: Int,
|
||||||
@JsonProperty("jq_trans_overflow") val jqTransOverflow: String,
|
@param:JsonProperty("jq_trans_overflow") val jqTransOverflow: String,
|
||||||
@JsonProperty("last_close") val lastClose: LastClose,
|
@param:JsonProperty("last_close") val lastClose: LastClose,
|
||||||
@JsonProperty("load_base") val loadBase: Int,
|
@param:JsonProperty("load_base") val loadBase: Int,
|
||||||
@JsonProperty("load_factor") val loadFactor: Int,
|
@param:JsonProperty("load_factor") val loadFactor: Int,
|
||||||
@JsonProperty("load_factor_fee_escalation") val loadFactorFeeEscalation: Int,
|
@param:JsonProperty("load_factor_fee_escalation") val loadFactorFeeEscalation: Int,
|
||||||
@JsonProperty("load_factor_fee_queue") val loadFactorFeeQueue: Int,
|
@param:JsonProperty("load_factor_fee_queue") val loadFactorFeeQueue: Int,
|
||||||
@JsonProperty("load_factor_fee_reference") val loadFactorFeeReference: Int,
|
@param:JsonProperty("load_factor_fee_reference") val loadFactorFeeReference: Int,
|
||||||
@JsonProperty("load_factor_server") val loadFactorServer: Int,
|
@param:JsonProperty("load_factor_server") val loadFactorServer: Int,
|
||||||
@JsonProperty("network_id") val networkId: Int,
|
@param:JsonProperty("network_id") val networkId: Int,
|
||||||
@JsonProperty("peer_disconnects") val peerDisconnects: String?,
|
@param:JsonProperty("peer_disconnects") val peerDisconnects: String?,
|
||||||
@JsonProperty("peer_disconnects_resources") val peerDisconnectsResources: String?,
|
@param:JsonProperty("peer_disconnects_resources") val peerDisconnectsResources: String?,
|
||||||
@JsonProperty("peers") val peers: Int,
|
@param:JsonProperty("peers") val peers: Int,
|
||||||
@JsonProperty("ports") val ports: List<Port>,
|
@param:JsonProperty("ports") val ports: List<Port>,
|
||||||
@JsonProperty("pubkey_node") val pubkeyNode: String?,
|
@param:JsonProperty("pubkey_node") val pubkeyNode: String?,
|
||||||
@JsonProperty("server_state") val serverState: String?,
|
@param:JsonProperty("server_state") val serverState: String?,
|
||||||
@JsonProperty("server_state_duration_us") val serverStateDurationUs: String?,
|
@param:JsonProperty("server_state_duration_us") val serverStateDurationUs: String?,
|
||||||
@JsonProperty("state_accounting") val stateAccounting: StateAccounting?,
|
@param:JsonProperty("state_accounting") val stateAccounting: StateAccounting?,
|
||||||
@JsonProperty("time") val time: String,
|
@param:JsonProperty("time") val time: String,
|
||||||
@JsonProperty("uptime") val uptime: Long,
|
@param:JsonProperty("uptime") val uptime: Long,
|
||||||
@JsonProperty("validated_ledger") val validatedLedger: ValidatedLedger,
|
@param:JsonProperty("validated_ledger") val validatedLedger: ValidatedLedger,
|
||||||
@JsonProperty("validation_quorum") val validationQuorum: Int,
|
@param:JsonProperty("validation_quorum") val validationQuorum: Int,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class LastClose(
|
data class LastClose(
|
||||||
@JsonProperty("converge_time") val convergeTime: Int,
|
@param:JsonProperty("converge_time") val convergeTime: Int,
|
||||||
@JsonProperty("proposers") val proposers: Int,
|
@param:JsonProperty("proposers") val proposers: Int,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class Port(
|
data class Port(
|
||||||
@JsonProperty("port") val port: String,
|
@param:JsonProperty("port") val port: String,
|
||||||
@JsonProperty("protocol") val protocol: List<String>,
|
@param:JsonProperty("protocol") val protocol: List<String>,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class StateAccounting(
|
data class StateAccounting(
|
||||||
@JsonProperty("connected") val connected: StateDuration,
|
@param:JsonProperty("connected") val connected: StateDuration,
|
||||||
@JsonProperty("disconnected") val disconnected: StateDuration,
|
@param:JsonProperty("disconnected") val disconnected: StateDuration,
|
||||||
@JsonProperty("full") val full: StateDuration,
|
@param:JsonProperty("full") val full: StateDuration,
|
||||||
@JsonProperty("syncing") val syncing: StateDuration,
|
@param:JsonProperty("syncing") val syncing: StateDuration,
|
||||||
@JsonProperty("tracking") val tracking: StateDuration,
|
@param:JsonProperty("tracking") val tracking: StateDuration,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class StateDuration(
|
data class StateDuration(
|
||||||
@JsonProperty("duration_us") val durationUs: String,
|
@param:JsonProperty("duration_us") val durationUs: String,
|
||||||
@JsonProperty("transitions") val transitions: String,
|
@param:JsonProperty("transitions") val transitions: String,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class ValidatedLedger(
|
data class ValidatedLedger(
|
||||||
@JsonProperty("base_fee") val baseFee: Int,
|
@param:JsonProperty("base_fee") val baseFee: Int,
|
||||||
@JsonProperty("close_time") val closeTime: Long,
|
@param:JsonProperty("close_time") val closeTime: Long,
|
||||||
@JsonProperty("hash") val hash: String,
|
@param:JsonProperty("hash") val hash: String,
|
||||||
@JsonProperty("reserve_base") val reserveBase: Long,
|
@param:JsonProperty("reserve_base") val reserveBase: Long,
|
||||||
@JsonProperty("reserve_inc") val reserveInc: Long,
|
@param:JsonProperty("reserve_inc") val reserveInc: Long,
|
||||||
@JsonProperty("seq") val seq: Long,
|
@param:JsonProperty("seq") val seq: Long,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ import org.bouncycastle.math.ec.ECPoint
|
|||||||
import org.bouncycastle.util.io.pem.PemObject
|
import org.bouncycastle.util.io.pem.PemObject
|
||||||
import org.bouncycastle.util.io.pem.PemReader
|
import org.bouncycastle.util.io.pem.PemReader
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.beans.factory.FactoryBean
|
import org.springframework.context.annotation.Bean
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
import org.springframework.context.annotation.Configuration
|
||||||
import org.springframework.stereotype.Repository
|
import org.springframework.stereotype.Component
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
@@ -20,10 +20,17 @@ import java.security.PublicKey
|
|||||||
import java.security.interfaces.ECPrivateKey
|
import java.security.interfaces.ECPrivateKey
|
||||||
import java.security.spec.PKCS8EncodedKeySpec
|
import java.security.spec.PKCS8EncodedKeySpec
|
||||||
|
|
||||||
@Repository
|
@Configuration
|
||||||
|
open class SignatureBeans {
|
||||||
|
@Bean
|
||||||
|
open fun signer(factory: ResponseSignerFactory): ResponseSigner =
|
||||||
|
factory.createSigner()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component
|
||||||
open class ResponseSignerFactory(
|
open class ResponseSignerFactory(
|
||||||
@Autowired private val config: SignatureConfig,
|
private val signatureConfig: SignatureConfig,
|
||||||
) : FactoryBean<ResponseSigner> {
|
) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val log = LoggerFactory.getLogger(ResponseSignerFactory::class.java)
|
private val log = LoggerFactory.getLogger(ResponseSignerFactory::class.java)
|
||||||
@@ -70,19 +77,15 @@ open class ResponseSignerFactory(
|
|||||||
return ByteBuffer.wrap(fullId).asLongBuffer().get()
|
return ByteBuffer.wrap(fullId).asLongBuffer().get()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getObject(): ResponseSigner {
|
fun createSigner(): ResponseSigner {
|
||||||
if (!config.enabled) {
|
if (!signatureConfig.enabled) {
|
||||||
return NoSigner()
|
return NoSigner()
|
||||||
}
|
}
|
||||||
if (config.privateKey == null) {
|
if (signatureConfig.privateKey == null) {
|
||||||
log.warn("Private Key for response signature is not set")
|
log.warn("Private Key for response signature is not set")
|
||||||
return NoSigner()
|
return NoSigner()
|
||||||
}
|
}
|
||||||
val key = readKey(config.algorithm, config.privateKey!!)
|
val key = readKey(signatureConfig.algorithm, signatureConfig.privateKey!!)
|
||||||
return EcdsaSigner(key.first, key.second)
|
return EcdsaSigner(key.first, key.second)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getObjectType(): Class<*>? {
|
|
||||||
return ResponseSigner::class.java
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -167,24 +167,24 @@ object SolanaChainSpecific : AbstractChainSpecific() {
|
|||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class SolanaWrapper(
|
data class SolanaWrapper(
|
||||||
@JsonProperty("context") var context: SolanaContext,
|
@param:JsonProperty("context") var context: SolanaContext,
|
||||||
@JsonProperty("value") var value: SolanaResult,
|
@param:JsonProperty("value") var value: SolanaResult,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class SolanaContext(
|
data class SolanaContext(
|
||||||
@JsonProperty("slot") var slot: Long,
|
@param:JsonProperty("slot") var slot: Long,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class SolanaResult(
|
data class SolanaResult(
|
||||||
@JsonProperty("block") var block: SolanaBlock,
|
@param:JsonProperty("block") var block: SolanaBlock,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class SolanaBlock(
|
data class SolanaBlock(
|
||||||
@JsonProperty("blockHeight") var height: Long,
|
@param:JsonProperty("blockHeight") var height: Long,
|
||||||
@JsonProperty("blockTime") var timestamp: Long,
|
@param:JsonProperty("blockTime") var timestamp: Long,
|
||||||
@JsonProperty("blockhash") var hash: String,
|
@param:JsonProperty("blockhash") var hash: String,
|
||||||
@JsonProperty("previousBlockhash") var parent: String,
|
@param:JsonProperty("previousBlockhash") var parent: String,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ class SolanaUpstreamSettingsDetector(
|
|||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
private data class SolanaVersion(
|
private data class SolanaVersion(
|
||||||
@JsonProperty("solana-core")
|
@param:JsonProperty("solana-core")
|
||||||
val version: String,
|
val version: String,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -119,14 +119,14 @@ object StarknetChainSpecific : AbstractPollChainSpecific() {
|
|||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class StarknetBlock(
|
data class StarknetBlock(
|
||||||
@JsonProperty("block_hash") var hash: String,
|
@param:JsonProperty("block_hash") var hash: String,
|
||||||
@JsonProperty("block_number") var number: Long,
|
@param:JsonProperty("block_number") var number: Long,
|
||||||
@JsonProperty("timestamp") var timestamp: Instant,
|
@param:JsonProperty("timestamp") var timestamp: Instant,
|
||||||
@JsonProperty("parent_hash") var parent: String,
|
@param:JsonProperty("parent_hash") var parent: String,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class StarknetSyncing(
|
data class StarknetSyncing(
|
||||||
@JsonProperty("current_block_num") var current: Long,
|
@param:JsonProperty("current_block_num") var current: Long,
|
||||||
@JsonProperty("highest_block_num") var highest: Long,
|
@param:JsonProperty("highest_block_num") var highest: Long,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ class StarknetUpstreamSettingsDetector(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun detectNodeType(): Flux<Pair<String, String>?> {
|
private fun detectNodeType(): Flux<Pair<String, String>> {
|
||||||
return upstream
|
return upstream
|
||||||
.getIngressReader()
|
.getIngressReader()
|
||||||
.read(pathfinderVersionRequest())
|
.read(pathfinderVersionRequest())
|
||||||
|
|||||||
@@ -1,26 +1,9 @@
|
|||||||
|
|
||||||
|
|
||||||
spring:
|
spring:
|
||||||
application:
|
application:
|
||||||
max-metadata-size: ${MAX_METADATA_SIZE:16384}
|
max-metadata-size: ${MAX_METADATA_SIZE:16384}
|
||||||
name: ${DSHACKLE_APP_NAME:dshackle}
|
name: ${DSHACKLE_APP_NAME:dshackle}
|
||||||
zipkin:
|
|
||||||
enabled: ${ENABLE_COLLECT_SPANS:false}
|
|
||||||
base-url: ${ZIPKIN_URL:https://trace.drpc.dev/}
|
|
||||||
sleuth:
|
|
||||||
span-filter:
|
|
||||||
additional-span-name-patterns-to-ignore:
|
|
||||||
- "^grpcChannelExecutor$"
|
|
||||||
- ".+NativeSubscribe"
|
|
||||||
- ".+SubscribeHead"
|
|
||||||
- ".+SubscribeBalance"
|
|
||||||
- ".+SubscribeTxStatus"
|
|
||||||
- ".+SubscribeStatus"
|
|
||||||
- ".+SubscribeNodeStatus"
|
|
||||||
- ".+Describe"
|
|
||||||
- ".+ServerReflectionInfo"
|
|
||||||
|
|
||||||
spans:
|
|
||||||
collect:
|
|
||||||
long-span-threshold: ${LONG_SPAN_THRESHOLD:1000}
|
|
||||||
|
|
||||||
compatibility:
|
compatibility:
|
||||||
enabled: ${DSHACKLE_COMPATIBILITY_ENABLED:true}
|
enabled: ${DSHACKLE_COMPATIBILITY_ENABLED:true}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
<!-- You can override this to have a custom pattern -->
|
<!-- You can override this to have a custom pattern -->
|
||||||
<property name="CONSOLE_LOG_PATTERN"
|
<property name="CONSOLE_LOG_PATTERN"
|
||||||
value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
|
value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) [%X{traceId},%X{spanId}] %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
|
||||||
|
|
||||||
<!-- Appender to log to console -->
|
<!-- Appender to log to console -->
|
||||||
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
|
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ import io.emeraldpay.dshackle.upstream.UpstreamAvailability
|
|||||||
import io.emeraldpay.dshackle.upstream.rpcclient.ListParams
|
import io.emeraldpay.dshackle.upstream.rpcclient.ListParams
|
||||||
import io.emeraldpay.dshackle.upstream.ethereum.rpc.RpcException
|
import io.emeraldpay.dshackle.upstream.ethereum.rpc.RpcException
|
||||||
import io.emeraldpay.dshackle.upstream.ethereum.rpc.RpcResponseError
|
import io.emeraldpay.dshackle.upstream.ethereum.rpc.RpcResponseError
|
||||||
import org.springframework.cloud.sleuth.Tracer
|
|
||||||
import reactor.core.publisher.Mono
|
import reactor.core.publisher.Mono
|
||||||
import reactor.test.StepVerifier
|
import reactor.test.StepVerifier
|
||||||
import spock.lang.Specification
|
import spock.lang.Specification
|
||||||
@@ -55,7 +54,7 @@ class QuorumRequestReaderSpec extends Specification {
|
|||||||
Chain.ETHEREUM__MAINNET,
|
Chain.ETHEREUM__MAINNET,
|
||||||
[up], Selector.empty
|
[up], Selector.empty
|
||||||
)
|
)
|
||||||
def reader = new QuorumRequestReader(apis, new AlwaysQuorum(), Stub(Tracer))
|
def reader = new QuorumRequestReader(apis, new AlwaysQuorum())
|
||||||
|
|
||||||
when:
|
when:
|
||||||
def act = reader.read(new ChainRequest("eth_test", new ListParams()))
|
def act = reader.read(new ChainRequest("eth_test", new ListParams()))
|
||||||
@@ -87,7 +86,7 @@ class QuorumRequestReaderSpec extends Specification {
|
|||||||
Chain.ETHEREUM__MAINNET,
|
Chain.ETHEREUM__MAINNET,
|
||||||
[up], Selector.empty
|
[up], Selector.empty
|
||||||
)
|
)
|
||||||
def reader = new QuorumRequestReader(apis, new AlwaysQuorum(), Stub(Tracer))
|
def reader = new QuorumRequestReader(apis, new AlwaysQuorum())
|
||||||
|
|
||||||
when:
|
when:
|
||||||
def act = reader.read(new ChainRequest("eth_test", new ListParams()))
|
def act = reader.read(new ChainRequest("eth_test", new ListParams()))
|
||||||
@@ -125,7 +124,7 @@ class QuorumRequestReaderSpec extends Specification {
|
|||||||
Chain.ETHEREUM__MAINNET,
|
Chain.ETHEREUM__MAINNET,
|
||||||
[up], Selector.empty
|
[up], Selector.empty
|
||||||
)
|
)
|
||||||
def reader = new QuorumRequestReader(apis, new AlwaysQuorum(), Stub(Tracer))
|
def reader = new QuorumRequestReader(apis, new AlwaysQuorum())
|
||||||
|
|
||||||
when:
|
when:
|
||||||
def act = reader.read(new ChainRequest("eth_test", new ListParams()))
|
def act = reader.read(new ChainRequest("eth_test", new ListParams()))
|
||||||
@@ -158,7 +157,7 @@ class QuorumRequestReaderSpec extends Specification {
|
|||||||
Chain.ETHEREUM__MAINNET,
|
Chain.ETHEREUM__MAINNET,
|
||||||
[up], Selector.empty
|
[up], Selector.empty
|
||||||
)
|
)
|
||||||
def reader = new QuorumRequestReader(apis, new NotNullQuorum(), Stub(Tracer))
|
def reader = new QuorumRequestReader(apis, new NotNullQuorum())
|
||||||
|
|
||||||
when:
|
when:
|
||||||
def act = reader.read(new ChainRequest("eth_test", new ListParams()))
|
def act = reader.read(new ChainRequest("eth_test", new ListParams()))
|
||||||
@@ -191,7 +190,7 @@ class QuorumRequestReaderSpec extends Specification {
|
|||||||
Chain.ETHEREUM__MAINNET,
|
Chain.ETHEREUM__MAINNET,
|
||||||
[up], Selector.empty
|
[up], Selector.empty
|
||||||
)
|
)
|
||||||
def reader = new QuorumRequestReader(apis, new NotNullQuorum(), Stub(Tracer))
|
def reader = new QuorumRequestReader(apis, new NotNullQuorum())
|
||||||
|
|
||||||
when:
|
when:
|
||||||
def act = reader.read(new ChainRequest("eth_test", new ListParams()))
|
def act = reader.read(new ChainRequest("eth_test", new ListParams()))
|
||||||
@@ -224,7 +223,7 @@ class QuorumRequestReaderSpec extends Specification {
|
|||||||
Chain.ETHEREUM__MAINNET,
|
Chain.ETHEREUM__MAINNET,
|
||||||
[up], Selector.empty
|
[up], Selector.empty
|
||||||
)
|
)
|
||||||
def reader = new QuorumRequestReader(apis, new NotNullQuorum(), Stub(Tracer))
|
def reader = new QuorumRequestReader(apis, new NotNullQuorum())
|
||||||
|
|
||||||
when:
|
when:
|
||||||
def act = reader.read(new ChainRequest("eth_test", new ListParams()))
|
def act = reader.read(new ChainRequest("eth_test", new ListParams()))
|
||||||
@@ -255,7 +254,7 @@ class QuorumRequestReaderSpec extends Specification {
|
|||||||
Chain.ETHEREUM__MAINNET,
|
Chain.ETHEREUM__MAINNET,
|
||||||
[up], Selector.empty
|
[up], Selector.empty
|
||||||
)
|
)
|
||||||
def reader = new QuorumRequestReader(apis, new AlwaysQuorum(), Stub(Tracer))
|
def reader = new QuorumRequestReader(apis, new AlwaysQuorum())
|
||||||
|
|
||||||
when:
|
when:
|
||||||
def act = reader.read(new ChainRequest("eth_test", new ListParams()))
|
def act = reader.read(new ChainRequest("eth_test", new ListParams()))
|
||||||
@@ -289,7 +288,7 @@ class QuorumRequestReaderSpec extends Specification {
|
|||||||
Chain.ETHEREUM__MAINNET,
|
Chain.ETHEREUM__MAINNET,
|
||||||
[up], Selector.empty
|
[up], Selector.empty
|
||||||
)
|
)
|
||||||
def reader = new QuorumRequestReader(apis, new NotLaggingQuorum(1), Stub(Tracer))
|
def reader = new QuorumRequestReader(apis, new NotLaggingQuorum(1))
|
||||||
|
|
||||||
when:
|
when:
|
||||||
def act = reader.read(new ChainRequest("eth_test", new ListParams()))
|
def act = reader.read(new ChainRequest("eth_test", new ListParams()))
|
||||||
@@ -315,7 +314,7 @@ class QuorumRequestReaderSpec extends Specification {
|
|||||||
Chain.ETHEREUM__MAINNET,
|
Chain.ETHEREUM__MAINNET,
|
||||||
[up], Selector.empty
|
[up], Selector.empty
|
||||||
)
|
)
|
||||||
def reader = new QuorumRequestReader(apis, new AlwaysQuorum(), Stub(Tracer))
|
def reader = new QuorumRequestReader(apis, new AlwaysQuorum())
|
||||||
|
|
||||||
when:
|
when:
|
||||||
def act = reader.read(new ChainRequest("eth_test", new ListParams()))
|
def act = reader.read(new ChainRequest("eth_test", new ListParams()))
|
||||||
@@ -365,7 +364,7 @@ class QuorumRequestReaderSpec extends Specification {
|
|||||||
new Selector.HeightMatcher(100000000),
|
new Selector.HeightMatcher(100000000),
|
||||||
)
|
)
|
||||||
))
|
))
|
||||||
def reader = new QuorumRequestReader(apis, new AlwaysQuorum(), Stub(Tracer))
|
def reader = new QuorumRequestReader(apis, new AlwaysQuorum())
|
||||||
|
|
||||||
when:
|
when:
|
||||||
def act = reader.read(new ChainRequest("eth_test", new ListParams()))
|
def act = reader.read(new ChainRequest("eth_test", new ListParams()))
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import io.emeraldpay.dshackle.upstream.ChainException
|
|||||||
import io.emeraldpay.dshackle.upstream.ChainRequest
|
import io.emeraldpay.dshackle.upstream.ChainRequest
|
||||||
import io.emeraldpay.dshackle.upstream.ChainResponse
|
import io.emeraldpay.dshackle.upstream.ChainResponse
|
||||||
import io.emeraldpay.dshackle.upstream.rpcclient.ListParams
|
import io.emeraldpay.dshackle.upstream.rpcclient.ListParams
|
||||||
import org.springframework.cloud.sleuth.Tracer
|
|
||||||
import reactor.core.publisher.Mono
|
import reactor.core.publisher.Mono
|
||||||
import reactor.test.StepVerifier
|
import reactor.test.StepVerifier
|
||||||
import spock.lang.Specification
|
import spock.lang.Specification
|
||||||
@@ -43,7 +42,7 @@ class BroadcastReaderSpec extends Specification {
|
|||||||
Mono.just(new ChainResponse(result, null))
|
Mono.just(new ChainResponse(result, null))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
def reader = new BroadcastReader([up, up1, up2], new Selector.EmptyMatcher(), null, new BroadcastQuorum(), Stub(Tracer))
|
def reader = new BroadcastReader([up, up1, up2], new Selector.EmptyMatcher(), null, new BroadcastQuorum())
|
||||||
when:
|
when:
|
||||||
def act = reader.read(new ChainRequest("eth_sendRawTransaction", new ListParams(["0x1"])))
|
def act = reader.read(new ChainRequest("eth_sendRawTransaction", new ListParams(["0x1"])))
|
||||||
then:
|
then:
|
||||||
@@ -81,7 +80,7 @@ class BroadcastReaderSpec extends Specification {
|
|||||||
1 * read(new ChainRequest("eth_sendRawTransaction", new ListParams(["0x1"]))) >>
|
1 * read(new ChainRequest("eth_sendRawTransaction", new ListParams(["0x1"]))) >>
|
||||||
Mono.error(new ChainException(1, "too low")) }
|
Mono.error(new ChainException(1, "too low")) }
|
||||||
}
|
}
|
||||||
def reader = new BroadcastReader([up, up1, up2], new Selector.EmptyMatcher(), null, new BroadcastQuorum(), Stub(Tracer))
|
def reader = new BroadcastReader([up, up1, up2], new Selector.EmptyMatcher(), null, new BroadcastQuorum())
|
||||||
when:
|
when:
|
||||||
def act = reader.read(new ChainRequest("eth_sendRawTransaction", new ListParams(["0x1"])))
|
def act = reader.read(new ChainRequest("eth_sendRawTransaction", new ListParams(["0x1"])))
|
||||||
then:
|
then:
|
||||||
@@ -114,7 +113,7 @@ class BroadcastReaderSpec extends Specification {
|
|||||||
0 * getId() >> "id"
|
0 * getId() >> "id"
|
||||||
0 * getIngressReader() >> Mock(Reader)
|
0 * getIngressReader() >> Mock(Reader)
|
||||||
}
|
}
|
||||||
def reader = new BroadcastReader([up, up1, up2], new Selector.EmptyMatcher(), null, new BroadcastQuorum(), Stub(Tracer))
|
def reader = new BroadcastReader([up, up1, up2], new Selector.EmptyMatcher(), null, new BroadcastQuorum())
|
||||||
when:
|
when:
|
||||||
def act = reader.read(new ChainRequest("eth_sendRawTransaction", new ListParams(["0x1"])))
|
def act = reader.read(new ChainRequest("eth_sendRawTransaction", new ListParams(["0x1"])))
|
||||||
then:
|
then:
|
||||||
@@ -152,7 +151,7 @@ class BroadcastReaderSpec extends Specification {
|
|||||||
Mono.error(new ChainException(1, "too low"))
|
Mono.error(new ChainException(1, "too low"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
def reader = new BroadcastReader([up, up1, up2], new Selector.EmptyMatcher(), null, new BroadcastQuorum(), Stub(Tracer))
|
def reader = new BroadcastReader([up, up1, up2], new Selector.EmptyMatcher(), null, new BroadcastQuorum())
|
||||||
when:
|
when:
|
||||||
def act = reader.read(new ChainRequest("eth_sendRawTransaction", new ListParams(["0x1"])))
|
def act = reader.read(new ChainRequest("eth_sendRawTransaction", new ListParams(["0x1"])))
|
||||||
then:
|
then:
|
||||||
@@ -178,7 +177,7 @@ class BroadcastReaderSpec extends Specification {
|
|||||||
0 * getId() >> "id"
|
0 * getId() >> "id"
|
||||||
0 * getIngressReader() >> Mock(Reader)
|
0 * getIngressReader() >> Mock(Reader)
|
||||||
}
|
}
|
||||||
def reader = new BroadcastReader([up, up1, up2], new Selector.EmptyMatcher(), null, new BroadcastQuorum(), Stub(Tracer))
|
def reader = new BroadcastReader([up, up1, up2], new Selector.EmptyMatcher(), null, new BroadcastQuorum())
|
||||||
when:
|
when:
|
||||||
def act = reader
|
def act = reader
|
||||||
.read(new ChainRequest("eth_sendRawTransaction", new ListParams(["0x1"])))
|
.read(new ChainRequest("eth_sendRawTransaction", new ListParams(["0x1"])))
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ import io.emeraldpay.dshackle.upstream.rpcclient.ListParams
|
|||||||
import io.emeraldpay.dshackle.upstream.signature.ResponseSigner
|
import io.emeraldpay.dshackle.upstream.signature.ResponseSigner
|
||||||
import io.emeraldpay.dshackle.upstream.ethereum.rpc.RpcException
|
import io.emeraldpay.dshackle.upstream.ethereum.rpc.RpcException
|
||||||
import io.emeraldpay.dshackle.upstream.ethereum.rpc.RpcResponseError
|
import io.emeraldpay.dshackle.upstream.ethereum.rpc.RpcResponseError
|
||||||
import org.springframework.cloud.sleuth.Tracer
|
|
||||||
import reactor.core.publisher.Flux
|
import reactor.core.publisher.Flux
|
||||||
import reactor.core.publisher.Mono
|
import reactor.core.publisher.Mono
|
||||||
import reactor.test.StepVerifier
|
import reactor.test.StepVerifier
|
||||||
@@ -67,7 +66,7 @@ class NativeCallSpec extends Specification {
|
|||||||
config.cache = cacheConfig
|
config.cache = cacheConfig
|
||||||
config.passthrough = passthrough
|
config.passthrough = passthrough
|
||||||
|
|
||||||
new NativeCall(upstreams, signer, config, Stub(Tracer))
|
new NativeCall(upstreams, signer, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
def "Tries router first"() {
|
def "Tries router first"() {
|
||||||
|
|||||||
@@ -45,10 +45,6 @@ class NativeSubscribeSpec extends Specification {
|
|||||||
}
|
}
|
||||||
def up = Mock(GenericMultistream) {
|
def up = Mock(GenericMultistream) {
|
||||||
1 * it.start()
|
1 * it.start()
|
||||||
_ * it.getSubscriptionTopics() >> {
|
|
||||||
println("getSubscriptionTopics called")
|
|
||||||
return ["newHeads"]
|
|
||||||
}
|
|
||||||
_ * it.tryProxySubscribe(_, _) >> {
|
_ * it.tryProxySubscribe(_, _) >> {
|
||||||
println("tryProxySubscribe called")
|
println("tryProxySubscribe called")
|
||||||
return null
|
return null
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import io.emeraldpay.dshackle.upstream.calls.DefaultEthereumMethods
|
|||||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumCachingReader
|
import io.emeraldpay.dshackle.upstream.ethereum.EthereumCachingReader
|
||||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumChainSpecific
|
import io.emeraldpay.dshackle.upstream.ethereum.EthereumChainSpecific
|
||||||
import org.jetbrains.annotations.NotNull
|
import org.jetbrains.annotations.NotNull
|
||||||
import org.springframework.cloud.sleuth.brave.bridge.BraveTracer
|
|
||||||
import reactor.core.scheduler.Schedulers
|
import reactor.core.scheduler.Schedulers
|
||||||
|
|
||||||
class MultistreamHolderMock implements MultistreamHolder {
|
class MultistreamHolderMock implements MultistreamHolder {
|
||||||
@@ -49,7 +48,7 @@ class MultistreamHolderMock implements MultistreamHolder {
|
|||||||
upstreams[chain] = new GenericMultistream(
|
upstreams[chain] = new GenericMultistream(
|
||||||
chain, Schedulers.immediate(), null, new ArrayList<Upstream>(), Caches.default(),
|
chain, Schedulers.immediate(), null, new ArrayList<Upstream>(), Caches.default(),
|
||||||
Schedulers.boundedElastic(),
|
Schedulers.boundedElastic(),
|
||||||
EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(TestingCommons.tracerMock()),
|
EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(),
|
||||||
EthereumChainSpecific.INSTANCE.&localReaderBuilder,
|
EthereumChainSpecific.INSTANCE.&localReaderBuilder,
|
||||||
io.emeraldpay.dshackle.upstream.starknet.StarknetChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()),
|
io.emeraldpay.dshackle.upstream.starknet.StarknetChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()),
|
||||||
)
|
)
|
||||||
@@ -102,7 +101,7 @@ class MultistreamHolderMock implements MultistreamHolder {
|
|||||||
|
|
||||||
EthereumMultistreamMock(@NotNull Chain chain, @NotNull List<GenericUpstream> upstreams, @NotNull Caches caches) {
|
EthereumMultistreamMock(@NotNull Chain chain, @NotNull List<GenericUpstream> upstreams, @NotNull Caches caches) {
|
||||||
super(chain, Schedulers.immediate(), null, upstreams, caches, Schedulers.boundedElastic(),
|
super(chain, Schedulers.immediate(), null, upstreams, caches, Schedulers.boundedElastic(),
|
||||||
EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(new BraveTracer(null, null, null)),
|
EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(),
|
||||||
EthereumChainSpecific.INSTANCE.&localReaderBuilder,
|
EthereumChainSpecific.INSTANCE.&localReaderBuilder,
|
||||||
EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()),
|
EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -52,10 +52,6 @@ class TestingCommons {
|
|||||||
return new ApiReaderMock()
|
return new ApiReaderMock()
|
||||||
}
|
}
|
||||||
|
|
||||||
static TracerMock tracerMock() {
|
|
||||||
return new TracerMock(null, null, null)
|
|
||||||
}
|
|
||||||
|
|
||||||
static GenericUpstreamMock upstream() {
|
static GenericUpstreamMock upstream() {
|
||||||
return new GenericUpstreamMock(Chain.ETHEREUM__MAINNET, api())
|
return new GenericUpstreamMock(Chain.ETHEREUM__MAINNET, api())
|
||||||
}
|
}
|
||||||
@@ -99,7 +95,7 @@ class TestingCommons {
|
|||||||
static Multistream multistream(GenericUpstreamMock up) {
|
static Multistream multistream(GenericUpstreamMock up) {
|
||||||
return new GenericMultistream(Chain.ETHEREUM__MAINNET, Schedulers.immediate(), null, new ArrayList<Upstream>(), Caches.default(),
|
return new GenericMultistream(Chain.ETHEREUM__MAINNET, Schedulers.immediate(), null, new ArrayList<Upstream>(), Caches.default(),
|
||||||
Schedulers.boundedElastic(),
|
Schedulers.boundedElastic(),
|
||||||
EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(tracerMock()),
|
EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(),
|
||||||
EthereumChainSpecific.INSTANCE.&localReaderBuilder,
|
EthereumChainSpecific.INSTANCE.&localReaderBuilder,
|
||||||
EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()),
|
EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()),
|
||||||
).tap {
|
).tap {
|
||||||
@@ -126,7 +122,7 @@ class TestingCommons {
|
|||||||
|
|
||||||
static Multistream multistreamWithoutUpstreams(Chain chain) {
|
static Multistream multistreamWithoutUpstreams(Chain chain) {
|
||||||
return new GenericMultistream(chain, Schedulers.immediate(), null, [], emptyCaches().getCaches(chain), Schedulers.boundedElastic(),
|
return new GenericMultistream(chain, Schedulers.immediate(), null, [], emptyCaches().getCaches(chain), Schedulers.boundedElastic(),
|
||||||
EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(tracerMock()),
|
EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(),
|
||||||
EthereumChainSpecific.INSTANCE.&localReaderBuilder,
|
EthereumChainSpecific.INSTANCE.&localReaderBuilder,
|
||||||
EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()),
|
EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()),
|
||||||
)
|
)
|
||||||
@@ -134,7 +130,7 @@ class TestingCommons {
|
|||||||
|
|
||||||
static Multistream multistreamClassicWithoutUpstreams(Chain chain) {
|
static Multistream multistreamClassicWithoutUpstreams(Chain chain) {
|
||||||
return new GenericMultistream(chain, Schedulers.immediate(), null, [], emptyCaches().getCaches(chain), Schedulers.boundedElastic(),
|
return new GenericMultistream(chain, Schedulers.immediate(), null, [], emptyCaches().getCaches(chain), Schedulers.boundedElastic(),
|
||||||
EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(tracerMock()),
|
EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(),
|
||||||
EthereumChainSpecific.INSTANCE.&localReaderBuilder,
|
EthereumChainSpecific.INSTANCE.&localReaderBuilder,
|
||||||
EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()),
|
EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,64 +0,0 @@
|
|||||||
package io.emeraldpay.dshackle.test
|
|
||||||
|
|
||||||
import brave.Tracer
|
|
||||||
import org.springframework.cloud.sleuth.CurrentTraceContext
|
|
||||||
import org.springframework.cloud.sleuth.Span
|
|
||||||
import org.springframework.cloud.sleuth.TraceContext
|
|
||||||
import org.springframework.cloud.sleuth.brave.bridge.BraveBaggageManager
|
|
||||||
import org.springframework.cloud.sleuth.brave.bridge.BraveSpan
|
|
||||||
import org.springframework.cloud.sleuth.brave.bridge.BraveTracer
|
|
||||||
import spock.mock.DetachedMockFactory
|
|
||||||
|
|
||||||
class TracerMock extends BraveTracer {
|
|
||||||
private final spanMock = new SpanMock(null)
|
|
||||||
private static final mockFactory = new DetachedMockFactory()
|
|
||||||
|
|
||||||
TracerMock(Tracer tracer, CurrentTraceContext context, BraveBaggageManager braveBaggageManager) {
|
|
||||||
super(tracer, context, braveBaggageManager)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
Span nextSpan(Span parent) {
|
|
||||||
return spanMock
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
Span currentSpan() {
|
|
||||||
return spanMock
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
SpanInScope withSpan(Span span) {
|
|
||||||
return mockFactory.Stub(SpanInScope)
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class SpanMock extends BraveSpan {
|
|
||||||
SpanMock(brave.Span delegate) {
|
|
||||||
super(delegate)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
Span start() {
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
Span name(String name) {
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
Span tag(String key, String value) {
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void end() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
TraceContext context() {
|
|
||||||
return mockFactory.Stub(TraceContext)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -55,7 +55,7 @@ class MultistreamSpec extends Specification {
|
|||||||
def up2 = new GenericUpstreamMock("test1", Chain.ETHEREUM__MAINNET, TestingCommons.api(), new DirectCallMethods(["eth_test2", "eth_test3"]))
|
def up2 = new GenericUpstreamMock("test1", Chain.ETHEREUM__MAINNET, TestingCommons.api(), new DirectCallMethods(["eth_test2", "eth_test3"]))
|
||||||
def aggr = new GenericMultistream(Chain.ETHEREUM__MAINNET, Schedulers.immediate(), null, [up1, up2], Caches.default(),
|
def aggr = new GenericMultistream(Chain.ETHEREUM__MAINNET, Schedulers.immediate(), null, [up1, up2], Caches.default(),
|
||||||
Schedulers.boundedElastic(),
|
Schedulers.boundedElastic(),
|
||||||
EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(TestingCommons.tracerMock()),
|
EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(),
|
||||||
EthereumChainSpecific.INSTANCE.&localReaderBuilder,
|
EthereumChainSpecific.INSTANCE.&localReaderBuilder,
|
||||||
EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()))
|
EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()))
|
||||||
when:
|
when:
|
||||||
@@ -190,7 +190,7 @@ class MultistreamSpec extends Specification {
|
|||||||
def up3 = TestingCommons.upstream("test-3", "external")
|
def up3 = TestingCommons.upstream("test-3", "external")
|
||||||
def multistream = new GenericMultistream(Chain.ETHEREUM__MAINNET, Schedulers.immediate(), null, [up1, up2, up3], Caches.default(),
|
def multistream = new GenericMultistream(Chain.ETHEREUM__MAINNET, Schedulers.immediate(), null, [up1, up2, up3], Caches.default(),
|
||||||
Schedulers.boundedElastic(),
|
Schedulers.boundedElastic(),
|
||||||
EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(TestingCommons.tracerMock()),
|
EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(),
|
||||||
EthereumChainSpecific.INSTANCE.&localReaderBuilder,
|
EthereumChainSpecific.INSTANCE.&localReaderBuilder,
|
||||||
EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()))
|
EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()))
|
||||||
|
|
||||||
@@ -263,7 +263,7 @@ class MultistreamSpec extends Specification {
|
|||||||
def up2 = new GenericUpstreamMock("test2", Chain.ETHEREUM__MAINNET, TestingCommons.api(), new DirectCallMethods(["eth_test1", "eth_test2"]))
|
def up2 = new GenericUpstreamMock("test2", Chain.ETHEREUM__MAINNET, TestingCommons.api(), new DirectCallMethods(["eth_test1", "eth_test2"]))
|
||||||
def ms = new GenericMultistream(Chain.ETHEREUM__MAINNET, Schedulers.immediate(), null, new ArrayList<GenericMultistream>(), Caches.default(),
|
def ms = new GenericMultistream(Chain.ETHEREUM__MAINNET, Schedulers.immediate(), null, new ArrayList<GenericMultistream>(), Caches.default(),
|
||||||
Schedulers.boundedElastic(),
|
Schedulers.boundedElastic(),
|
||||||
EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(TestingCommons.tracerMock()),
|
EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(),
|
||||||
EthereumChainSpecific.INSTANCE.&localReaderBuilder,
|
EthereumChainSpecific.INSTANCE.&localReaderBuilder,
|
||||||
EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()))
|
EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()))
|
||||||
when:
|
when:
|
||||||
@@ -294,7 +294,7 @@ class MultistreamSpec extends Specification {
|
|||||||
def up2 = new GenericUpstreamMock("test2", Chain.ETHEREUM__MAINNET, TestingCommons.api(), new DirectCallMethods(["eth_test1", "eth_test2"]))
|
def up2 = new GenericUpstreamMock("test2", Chain.ETHEREUM__MAINNET, TestingCommons.api(), new DirectCallMethods(["eth_test1", "eth_test2"]))
|
||||||
def ms = new GenericMultistream(Chain.ETHEREUM__MAINNET, Schedulers.immediate(), null, new ArrayList<GenericMultistream>(), Caches.default(),
|
def ms = new GenericMultistream(Chain.ETHEREUM__MAINNET, Schedulers.immediate(), null, new ArrayList<GenericMultistream>(), Caches.default(),
|
||||||
Schedulers.boundedElastic(),
|
Schedulers.boundedElastic(),
|
||||||
EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(TestingCommons.tracerMock()),
|
EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(),
|
||||||
EthereumChainSpecific.INSTANCE.&localReaderBuilder,
|
EthereumChainSpecific.INSTANCE.&localReaderBuilder,
|
||||||
EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()))
|
EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()))
|
||||||
def head1 = createBlock(250, "0x0d050c785de17179f935b9b93aca09c442964cc59972c71ae68e74731448401b")
|
def head1 = createBlock(250, "0x0d050c785de17179f935b9b93aca09c442964cc59972c71ae68e74731448401b")
|
||||||
@@ -329,7 +329,7 @@ class MultistreamSpec extends Specification {
|
|||||||
def up3 = TestingCommons.upstream("test-3", "external")
|
def up3 = TestingCommons.upstream("test-3", "external")
|
||||||
def multistream = new GenericMultistream(Chain.ETHEREUM__MAINNET, Schedulers.immediate(), null, new ArrayList<Upstream>(), Caches.default(),
|
def multistream = new GenericMultistream(Chain.ETHEREUM__MAINNET, Schedulers.immediate(), null, new ArrayList<Upstream>(), Caches.default(),
|
||||||
Schedulers.boundedElastic(),
|
Schedulers.boundedElastic(),
|
||||||
EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(TestingCommons.tracerMock()),
|
EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(),
|
||||||
EthereumChainSpecific.INSTANCE.&localReaderBuilder,
|
EthereumChainSpecific.INSTANCE.&localReaderBuilder,
|
||||||
EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()))
|
EthereumChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()))
|
||||||
multistream.processUpstreamsEvents(
|
multistream.processUpstreamsEvents(
|
||||||
@@ -367,7 +367,7 @@ class MultistreamSpec extends Specification {
|
|||||||
TestEthereumPosMultistream(@NotNull Chain chain, @NotNull List<GenericUpstream> upstreams, @NotNull Caches caches) {
|
TestEthereumPosMultistream(@NotNull Chain chain, @NotNull List<GenericUpstream> upstreams, @NotNull Caches caches) {
|
||||||
super(chain, Schedulers.immediate(), null, upstreams, caches,
|
super(chain, Schedulers.immediate(), null, upstreams, caches,
|
||||||
Schedulers.boundedElastic(),
|
Schedulers.boundedElastic(),
|
||||||
EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(TestingCommons.tracerMock()),
|
EthereumChainSpecific.INSTANCE.makeCachingReaderBuilder(),
|
||||||
EthereumChainSpecific.INSTANCE.&localReaderBuilder,
|
EthereumChainSpecific.INSTANCE.&localReaderBuilder,
|
||||||
StarknetChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()))
|
StarknetChainSpecific.INSTANCE.subscriptionBuilder(Schedulers.boundedElastic()))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package io.emeraldpay.dshackle.upstream.bitcoin
|
package io.emeraldpay.dshackle.upstream.bitcoin
|
||||||
|
|
||||||
import io.emeraldpay.dshackle.upstream.bitcoin.data.EsploraUnspent
|
import io.emeraldpay.dshackle.upstream.bitcoin.data.EsploraUnspent
|
||||||
|
import org.bitcoinj.core.Address
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copyright (c) 2020 EmeraldPay, Inc
|
* Copyright (c) 2020 EmeraldPay, Inc
|
||||||
@@ -18,13 +19,11 @@ import io.emeraldpay.dshackle.upstream.bitcoin.data.EsploraUnspent
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import org.bitcoinj.core.Address
|
|
||||||
import org.bitcoinj.params.MainNetParams
|
import org.bitcoinj.params.MainNetParams
|
||||||
import org.bitcoinj.params.TestNet3Params
|
import org.bitcoinj.params.TestNet3Params
|
||||||
import org.mockserver.integration.ClientAndServer
|
import org.mockserver.integration.ClientAndServer
|
||||||
import org.mockserver.model.HttpRequest
|
import org.mockserver.model.HttpRequest
|
||||||
import org.mockserver.model.HttpResponse
|
import org.mockserver.model.HttpResponse
|
||||||
import org.springframework.util.SocketUtils
|
|
||||||
import reactor.test.StepVerifier
|
import reactor.test.StepVerifier
|
||||||
import spock.lang.Specification
|
import spock.lang.Specification
|
||||||
|
|
||||||
@@ -33,11 +32,9 @@ import java.time.Duration
|
|||||||
class EsploraClientSpec extends Specification {
|
class EsploraClientSpec extends Specification {
|
||||||
|
|
||||||
ClientAndServer mockServer
|
ClientAndServer mockServer
|
||||||
int port = 23001
|
|
||||||
|
|
||||||
def setup() {
|
def setup() {
|
||||||
port = SocketUtils.findAvailableTcpPort(23001)
|
mockServer = ClientAndServer.startClientAndServer(0)
|
||||||
mockServer = ClientAndServer.startClientAndServer(port);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def cleanup() {
|
def cleanup() {
|
||||||
@@ -54,7 +51,7 @@ class EsploraClientSpec extends Specification {
|
|||||||
).respond(
|
).respond(
|
||||||
HttpResponse.response(responseJson)
|
HttpResponse.response(responseJson)
|
||||||
)
|
)
|
||||||
def client = new EsploraClient(new URI("http://localhost:${port}"), null, null)
|
def client = new EsploraClient(new URI("http://localhost:${mockServer.port}"), null, null)
|
||||||
when:
|
when:
|
||||||
def act = client.getUtxo(Address.fromString(new MainNetParams(), "35vktkPo4wdK8Twu4VMiuPLdCx23XEykGY"))
|
def act = client.getUtxo(Address.fromString(new MainNetParams(), "35vktkPo4wdK8Twu4VMiuPLdCx23XEykGY"))
|
||||||
|
|
||||||
@@ -95,7 +92,7 @@ class EsploraClientSpec extends Specification {
|
|||||||
).respond(
|
).respond(
|
||||||
HttpResponse.response(responseJson)
|
HttpResponse.response(responseJson)
|
||||||
)
|
)
|
||||||
def client = new EsploraClient(new URI("http://localhost:${port}"), null, null)
|
def client = new EsploraClient(new URI("http://localhost:${mockServer.port}"), null, null)
|
||||||
when:
|
when:
|
||||||
def act = client.getTransactions(Address.fromString(TestNet3Params.get(), "tb1qyatuwvkfx8thy2ntmtuea6v42vp3zefqvll8kx"))
|
def act = client.getTransactions(Address.fromString(TestNet3Params.get(), "tb1qyatuwvkfx8thy2ntmtuea6v42vp3zefqvll8kx"))
|
||||||
|
|
||||||
@@ -125,7 +122,7 @@ class EsploraClientSpec extends Specification {
|
|||||||
).respond(
|
).respond(
|
||||||
HttpResponse.response("[]")
|
HttpResponse.response("[]")
|
||||||
)
|
)
|
||||||
def client = new EsploraClient(new URI("http://localhost:${port}"), null, null)
|
def client = new EsploraClient(new URI("http://localhost:${mockServer.port}"), null, null)
|
||||||
when:
|
when:
|
||||||
def act = client.getTransactions(Address.fromString(TestNet3Params.get(), "tb1qyatuwvkfx8thy2ntmtuea6v42vp3zefqvll8kx"))
|
def act = client.getTransactions(Address.fromString(TestNet3Params.get(), "tb1qyatuwvkfx8thy2ntmtuea6v42vp3zefqvll8kx"))
|
||||||
|
|
||||||
|
|||||||
@@ -8,19 +8,18 @@ import io.emeraldpay.dshackle.data.BlockId
|
|||||||
import io.emeraldpay.dshackle.data.DefaultContainer
|
import io.emeraldpay.dshackle.data.DefaultContainer
|
||||||
import io.emeraldpay.dshackle.reader.RequestReader
|
import io.emeraldpay.dshackle.reader.RequestReader
|
||||||
import io.emeraldpay.dshackle.reader.RequestReaderFactory
|
import io.emeraldpay.dshackle.reader.RequestReaderFactory
|
||||||
import io.emeraldpay.dshackle.test.TestingCommons
|
|
||||||
import io.emeraldpay.dshackle.upstream.*
|
import io.emeraldpay.dshackle.upstream.*
|
||||||
import io.emeraldpay.dshackle.upstream.calls.DefaultEthereumMethods
|
import io.emeraldpay.dshackle.upstream.calls.DefaultEthereumMethods
|
||||||
import io.emeraldpay.dshackle.upstream.ethereum.json.BlockJson
|
|
||||||
import io.emeraldpay.dshackle.upstream.finalization.FinalizationType
|
|
||||||
import io.emeraldpay.dshackle.upstream.rpcclient.ListParams
|
|
||||||
import io.emeraldpay.dshackle.upstream.ethereum.domain.Address
|
import io.emeraldpay.dshackle.upstream.ethereum.domain.Address
|
||||||
import io.emeraldpay.dshackle.upstream.ethereum.domain.BlockHash
|
import io.emeraldpay.dshackle.upstream.ethereum.domain.BlockHash
|
||||||
import io.emeraldpay.dshackle.upstream.ethereum.domain.TransactionId
|
import io.emeraldpay.dshackle.upstream.ethereum.domain.TransactionId
|
||||||
import io.emeraldpay.dshackle.upstream.ethereum.domain.Wei
|
import io.emeraldpay.dshackle.upstream.ethereum.domain.Wei
|
||||||
|
import io.emeraldpay.dshackle.upstream.ethereum.json.BlockJson
|
||||||
import io.emeraldpay.dshackle.upstream.ethereum.json.TransactionJson
|
import io.emeraldpay.dshackle.upstream.ethereum.json.TransactionJson
|
||||||
import io.emeraldpay.dshackle.upstream.ethereum.json.TransactionLogJson
|
import io.emeraldpay.dshackle.upstream.ethereum.json.TransactionLogJson
|
||||||
import io.emeraldpay.dshackle.upstream.ethereum.json.TransactionReceiptJson
|
import io.emeraldpay.dshackle.upstream.ethereum.json.TransactionReceiptJson
|
||||||
|
import io.emeraldpay.dshackle.upstream.finalization.FinalizationType
|
||||||
|
import io.emeraldpay.dshackle.upstream.rpcclient.ListParams
|
||||||
import org.apache.commons.collections4.Factory
|
import org.apache.commons.collections4.Factory
|
||||||
import reactor.core.publisher.Mono
|
import reactor.core.publisher.Mono
|
||||||
import reactor.test.StepVerifier
|
import reactor.test.StepVerifier
|
||||||
@@ -48,7 +47,7 @@ class EthereumDirectReaderSpec extends Specification {
|
|||||||
1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET)
|
1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET)
|
||||||
}
|
}
|
||||||
EthereumDirectReader reader = new EthereumDirectReader(
|
EthereumDirectReader reader = new EthereumDirectReader(
|
||||||
Stub(Multistream), Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock()
|
Stub(Multistream), Caches.default(), new CurrentBlockCache(), calls
|
||||||
)
|
)
|
||||||
reader.requestReaderFactory = Mock(RequestReaderFactory) {
|
reader.requestReaderFactory = Mock(RequestReaderFactory) {
|
||||||
1 * create({ it.upstreamFilter.sort == Selector.Sort.safe }) >> Mock(RequestReader) {
|
1 * create({ it.upstreamFilter.sort == Selector.Sort.safe }) >> Mock(RequestReader) {
|
||||||
@@ -83,7 +82,7 @@ class EthereumDirectReaderSpec extends Specification {
|
|||||||
1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET)
|
1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET)
|
||||||
}
|
}
|
||||||
EthereumDirectReader reader = new EthereumDirectReader(
|
EthereumDirectReader reader = new EthereumDirectReader(
|
||||||
Stub(Multistream), Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock()
|
Stub(Multistream), Caches.default(), new CurrentBlockCache(), calls
|
||||||
)
|
)
|
||||||
reader.requestReaderFactory = Mock(RequestReaderFactory) {
|
reader.requestReaderFactory = Mock(RequestReaderFactory) {
|
||||||
1 * create(_) >> Mock(RequestReader) {
|
1 * create(_) >> Mock(RequestReader) {
|
||||||
@@ -110,7 +109,7 @@ class EthereumDirectReaderSpec extends Specification {
|
|||||||
1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET)
|
1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET)
|
||||||
}
|
}
|
||||||
EthereumDirectReader reader = new EthereumDirectReader(
|
EthereumDirectReader reader = new EthereumDirectReader(
|
||||||
Stub(Multistream), Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock()
|
Stub(Multistream), Caches.default(), new CurrentBlockCache(), calls
|
||||||
)
|
)
|
||||||
reader.requestReaderFactory = Mock(RequestReaderFactory) {
|
reader.requestReaderFactory = Mock(RequestReaderFactory) {
|
||||||
1 * create(_) >> Mock(RequestReader) {
|
1 * create(_) >> Mock(RequestReader) {
|
||||||
@@ -143,7 +142,7 @@ class EthereumDirectReaderSpec extends Specification {
|
|||||||
1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET)
|
1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET)
|
||||||
}
|
}
|
||||||
EthereumDirectReader reader = new EthereumDirectReader(
|
EthereumDirectReader reader = new EthereumDirectReader(
|
||||||
Stub(Multistream), Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock()
|
Stub(Multistream), Caches.default(), new CurrentBlockCache(), calls
|
||||||
)
|
)
|
||||||
reader.requestReaderFactory = Mock(RequestReaderFactory) {
|
reader.requestReaderFactory = Mock(RequestReaderFactory) {
|
||||||
1 * create(_) >> Mock(RequestReader) {
|
1 * create(_) >> Mock(RequestReader) {
|
||||||
@@ -175,7 +174,7 @@ class EthereumDirectReaderSpec extends Specification {
|
|||||||
1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET)
|
1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET)
|
||||||
}
|
}
|
||||||
EthereumDirectReader reader = new EthereumDirectReader(
|
EthereumDirectReader reader = new EthereumDirectReader(
|
||||||
Stub(Multistream), Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock()
|
Stub(Multistream), Caches.default(), new CurrentBlockCache(), calls
|
||||||
)
|
)
|
||||||
reader.requestReaderFactory = Mock(RequestReaderFactory) {
|
reader.requestReaderFactory = Mock(RequestReaderFactory) {
|
||||||
1 * create(_) >> Mock(RequestReader) {
|
1 * create(_) >> Mock(RequestReader) {
|
||||||
@@ -208,7 +207,7 @@ class EthereumDirectReaderSpec extends Specification {
|
|||||||
1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET)
|
1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET)
|
||||||
}
|
}
|
||||||
EthereumDirectReader reader = new EthereumDirectReader(
|
EthereumDirectReader reader = new EthereumDirectReader(
|
||||||
Stub(Multistream), Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock()
|
Stub(Multistream), Caches.default(), new CurrentBlockCache(), calls
|
||||||
)
|
)
|
||||||
reader.requestReaderFactory = Mock(RequestReaderFactory) {
|
reader.requestReaderFactory = Mock(RequestReaderFactory) {
|
||||||
1 * create(_) >> Mock(RequestReader) {
|
1 * create(_) >> Mock(RequestReader) {
|
||||||
@@ -241,7 +240,7 @@ class EthereumDirectReaderSpec extends Specification {
|
|||||||
1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET)
|
1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET)
|
||||||
}
|
}
|
||||||
EthereumDirectReader reader = new EthereumDirectReader(
|
EthereumDirectReader reader = new EthereumDirectReader(
|
||||||
Stub(Multistream), Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock()
|
Stub(Multistream), Caches.default(), new CurrentBlockCache(), calls
|
||||||
)
|
)
|
||||||
reader.requestReaderFactory = Mock(RequestReaderFactory) {
|
reader.requestReaderFactory = Mock(RequestReaderFactory) {
|
||||||
1 * create(_) >> Mock(RequestReader) {
|
1 * create(_) >> Mock(RequestReader) {
|
||||||
@@ -275,7 +274,7 @@ class EthereumDirectReaderSpec extends Specification {
|
|||||||
1 * cacheReceipt(Caches.Tag.REQUESTED, { DefaultContainer data -> data.txId.toHex() == hash1.substring(2) && data.height == 100 })
|
1 * cacheReceipt(Caches.Tag.REQUESTED, { DefaultContainer data -> data.txId.toHex() == hash1.substring(2) && data.height == 100 })
|
||||||
}
|
}
|
||||||
EthereumDirectReader reader = new EthereumDirectReader(
|
EthereumDirectReader reader = new EthereumDirectReader(
|
||||||
Stub(Multistream), caches, new CurrentBlockCache(), calls, TestingCommons.tracerMock()
|
Stub(Multistream), caches, new CurrentBlockCache(), calls
|
||||||
)
|
)
|
||||||
reader.requestReaderFactory = Mock(RequestReaderFactory) {
|
reader.requestReaderFactory = Mock(RequestReaderFactory) {
|
||||||
1 * create(_) >> Mock(RequestReader) {
|
1 * create(_) >> Mock(RequestReader) {
|
||||||
@@ -300,7 +299,7 @@ class EthereumDirectReaderSpec extends Specification {
|
|||||||
1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET)
|
1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET)
|
||||||
}
|
}
|
||||||
EthereumDirectReader reader = new EthereumDirectReader(
|
EthereumDirectReader reader = new EthereumDirectReader(
|
||||||
Stub(Multistream), Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock()
|
Stub(Multistream), Caches.default(), new CurrentBlockCache(), calls
|
||||||
)
|
)
|
||||||
reader.requestReaderFactory = Mock(RequestReaderFactory) {
|
reader.requestReaderFactory = Mock(RequestReaderFactory) {
|
||||||
1 * create(_) >> Mock(RequestReader) {
|
1 * create(_) >> Mock(RequestReader) {
|
||||||
@@ -330,7 +329,7 @@ class EthereumDirectReaderSpec extends Specification {
|
|||||||
1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET)
|
1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET)
|
||||||
}
|
}
|
||||||
EthereumDirectReader reader = new EthereumDirectReader(
|
EthereumDirectReader reader = new EthereumDirectReader(
|
||||||
up, Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock()
|
up, Caches.default(), new CurrentBlockCache(), calls
|
||||||
)
|
)
|
||||||
reader.requestReaderFactory = Mock(RequestReaderFactory) {
|
reader.requestReaderFactory = Mock(RequestReaderFactory) {
|
||||||
1 * create(_) >> Mock(RequestReader) {
|
1 * create(_) >> Mock(RequestReader) {
|
||||||
@@ -361,7 +360,7 @@ class EthereumDirectReaderSpec extends Specification {
|
|||||||
1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET)
|
1 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET)
|
||||||
}
|
}
|
||||||
EthereumDirectReader reader = new EthereumDirectReader(
|
EthereumDirectReader reader = new EthereumDirectReader(
|
||||||
up, Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock()
|
up, Caches.default(), new CurrentBlockCache(), calls
|
||||||
)
|
)
|
||||||
reader.requestReaderFactory = Mock(RequestReaderFactory) {
|
reader.requestReaderFactory = Mock(RequestReaderFactory) {
|
||||||
1 * create(_) >> Mock(RequestReader) {
|
1 * create(_) >> Mock(RequestReader) {
|
||||||
@@ -399,7 +398,7 @@ class EthereumDirectReaderSpec extends Specification {
|
|||||||
Global.objectMapper.writeValueAsBytes(json), null, 1, data, null)
|
Global.objectMapper.writeValueAsBytes(json), null, 1, data, null)
|
||||||
)
|
)
|
||||||
EthereumDirectReader ethereumDirectReader = new EthereumDirectReader(
|
EthereumDirectReader ethereumDirectReader = new EthereumDirectReader(
|
||||||
Stub(Multistream), Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock()
|
Stub(Multistream), Caches.default(), new CurrentBlockCache(), calls
|
||||||
)
|
)
|
||||||
ethereumDirectReader.requestReaderFactory = Mock(RequestReaderFactory) {
|
ethereumDirectReader.requestReaderFactory = Mock(RequestReaderFactory) {
|
||||||
2 * create(_) >> Mock(RequestReader) {
|
2 * create(_) >> Mock(RequestReader) {
|
||||||
@@ -439,7 +438,7 @@ class EthereumDirectReaderSpec extends Specification {
|
|||||||
Global.objectMapper.writeValueAsBytes(json), null, 1, data, null)
|
Global.objectMapper.writeValueAsBytes(json), null, 1, data, null)
|
||||||
)
|
)
|
||||||
EthereumDirectReader ethereumDirectReader = new EthereumDirectReader(
|
EthereumDirectReader ethereumDirectReader = new EthereumDirectReader(
|
||||||
Stub(Multistream), Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock()
|
Stub(Multistream), Caches.default(), new CurrentBlockCache(), calls
|
||||||
)
|
)
|
||||||
ethereumDirectReader.requestReaderFactory = Mock(RequestReaderFactory) {
|
ethereumDirectReader.requestReaderFactory = Mock(RequestReaderFactory) {
|
||||||
2 * create(_) >> Mock(RequestReader) {
|
2 * create(_) >> Mock(RequestReader) {
|
||||||
@@ -472,7 +471,7 @@ class EthereumDirectReaderSpec extends Specification {
|
|||||||
4 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET)
|
4 * create() >> new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET)
|
||||||
}
|
}
|
||||||
EthereumDirectReader reader = new EthereumDirectReader(
|
EthereumDirectReader reader = new EthereumDirectReader(
|
||||||
up, Caches.default(), new CurrentBlockCache(), calls, TestingCommons.tracerMock()
|
up, Caches.default(), new CurrentBlockCache(), calls
|
||||||
)
|
)
|
||||||
reader.requestReaderFactory = Mock(RequestReaderFactory) {
|
reader.requestReaderFactory = Mock(RequestReaderFactory) {
|
||||||
4 * create(_) >> Mock(RequestReader) {
|
4 * create(_) >> Mock(RequestReader) {
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ class EthereumLocalReaderSpec extends Specification {
|
|||||||
TestingCommons.multistream(TestingCommons.api()),
|
TestingCommons.multistream(TestingCommons.api()),
|
||||||
Caches.default(),
|
Caches.default(),
|
||||||
ConstantFactory.constantFactory(new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET)),
|
ConstantFactory.constantFactory(new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET)),
|
||||||
TestingCommons.tracerMock()
|
|
||||||
),
|
),
|
||||||
methods
|
methods
|
||||||
)
|
)
|
||||||
@@ -39,7 +38,6 @@ class EthereumLocalReaderSpec extends Specification {
|
|||||||
TestingCommons.multistream(TestingCommons.api()),
|
TestingCommons.multistream(TestingCommons.api()),
|
||||||
Caches.default(),
|
Caches.default(),
|
||||||
ConstantFactory.constantFactory(new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET)),
|
ConstantFactory.constantFactory(new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET)),
|
||||||
TestingCommons.tracerMock()
|
|
||||||
),
|
),
|
||||||
methods
|
methods
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import io.micrometer.core.instrument.Timer
|
|||||||
import org.mockserver.integration.ClientAndServer
|
import org.mockserver.integration.ClientAndServer
|
||||||
import org.mockserver.model.HttpRequest
|
import org.mockserver.model.HttpRequest
|
||||||
import org.mockserver.model.HttpResponse
|
import org.mockserver.model.HttpResponse
|
||||||
import org.springframework.util.SocketUtils
|
|
||||||
import reactor.core.scheduler.Schedulers
|
import reactor.core.scheduler.Schedulers
|
||||||
import spock.lang.Specification
|
import spock.lang.Specification
|
||||||
|
|
||||||
@@ -35,7 +34,6 @@ import java.time.Duration
|
|||||||
class JsonRpcHttpReaderSpec extends Specification {
|
class JsonRpcHttpReaderSpec extends Specification {
|
||||||
|
|
||||||
ClientAndServer mockServer
|
ClientAndServer mockServer
|
||||||
int port = 19332
|
|
||||||
RequestMetrics metrics = new RequestMetrics(
|
RequestMetrics metrics = new RequestMetrics(
|
||||||
Timer.builder("test1").register(TestingCommons.meterRegistry),
|
Timer.builder("test1").register(TestingCommons.meterRegistry),
|
||||||
Counter.builder("test2").register(TestingCommons.meterRegistry),
|
Counter.builder("test2").register(TestingCommons.meterRegistry),
|
||||||
@@ -43,8 +41,7 @@ class JsonRpcHttpReaderSpec extends Specification {
|
|||||||
)
|
)
|
||||||
|
|
||||||
def setup() {
|
def setup() {
|
||||||
port = SocketUtils.findAvailableTcpPort(19332)
|
mockServer = ClientAndServer.startClientAndServer(0);
|
||||||
mockServer = ClientAndServer.startClientAndServer(port);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def cleanup() {
|
def cleanup() {
|
||||||
@@ -53,7 +50,7 @@ class JsonRpcHttpReaderSpec extends Specification {
|
|||||||
|
|
||||||
def "Make a request"() {
|
def "Make a request"() {
|
||||||
setup:
|
setup:
|
||||||
JsonRpcHttpReader client = new JsonRpcHttpReader("localhost:${port}", 50, 50, metrics, Schedulers.boundedElastic(),null, null, [:])
|
JsonRpcHttpReader client = new JsonRpcHttpReader("localhost:${mockServer.port}", 50, 50, metrics, Schedulers.boundedElastic(),null, null, [:])
|
||||||
def resp = '{' +
|
def resp = '{' +
|
||||||
' "jsonrpc": "2.0",' +
|
' "jsonrpc": "2.0",' +
|
||||||
' "result": "0x98de45",' +
|
' "result": "0x98de45",' +
|
||||||
@@ -74,7 +71,7 @@ class JsonRpcHttpReaderSpec extends Specification {
|
|||||||
|
|
||||||
def "Produces RPC Exception on error status code"() {
|
def "Produces RPC Exception on error status code"() {
|
||||||
setup:
|
setup:
|
||||||
def client = new JsonRpcHttpReader("localhost:${port}", 50, 50, metrics, Schedulers.boundedElastic(), null, null, [:])
|
def client = new JsonRpcHttpReader("localhost:${mockServer.port}", 50, 50, metrics, Schedulers.boundedElastic(), null, null, [:])
|
||||||
mockServer.when(
|
mockServer.when(
|
||||||
HttpRequest.request()
|
HttpRequest.request()
|
||||||
).respond(
|
).respond(
|
||||||
@@ -97,7 +94,7 @@ class JsonRpcHttpReaderSpec extends Specification {
|
|||||||
|
|
||||||
def "Tries to extract message if HTTP error if it still contains a JSON RPC message"() {
|
def "Tries to extract message if HTTP error if it still contains a JSON RPC message"() {
|
||||||
setup:
|
setup:
|
||||||
def client = new JsonRpcHttpReader("localhost:${port}", 50, 50, metrics, Schedulers.boundedElastic(), null, null, [:])
|
def client = new JsonRpcHttpReader("localhost:${mockServer.port}", 50, 50, metrics, Schedulers.boundedElastic(), null, null, [:])
|
||||||
|
|
||||||
mockServer.when(
|
mockServer.when(
|
||||||
HttpRequest.request()
|
HttpRequest.request()
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ class EcdsaSignerSpec extends Specification {
|
|||||||
def conf = new SignatureConfig()
|
def conf = new SignatureConfig()
|
||||||
conf.enabled = true
|
conf.enabled = true
|
||||||
conf.privateKey = "src/test/resources/signer/test_key"
|
conf.privateKey = "src/test/resources/signer/test_key"
|
||||||
def signer = new ResponseSignerFactory(conf).getObject() as EcdsaSigner
|
def signer = new ResponseSignerFactory(conf).createSigner() as EcdsaSigner
|
||||||
|
|
||||||
// To verify the test, check the hash of test key above:
|
// To verify the test, check the hash of test key above:
|
||||||
//
|
//
|
||||||
@@ -123,7 +123,7 @@ class EcdsaSignerSpec extends Specification {
|
|||||||
verifier.initVerify(pk)
|
verifier.initVerify(pk)
|
||||||
verifier.update("DSHACKLESIG/10/infura/${Hex.encodeHexString(sha256.digest(result))}".getBytes())
|
verifier.update("DSHACKLESIG/10/infura/${Hex.encodeHexString(sha256.digest(result))}".getBytes())
|
||||||
|
|
||||||
def signer = factory.getObject() as EcdsaSigner
|
def signer = factory.createSigner() as EcdsaSigner
|
||||||
|
|
||||||
when:
|
when:
|
||||||
def sig = signer.sign(10, result, up.id)
|
def sig = signer.sign(10, result, up.id)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ class ResponseSignerFactorySpec extends Specification {
|
|||||||
setup:
|
setup:
|
||||||
def conf = new SignatureConfig()
|
def conf = new SignatureConfig()
|
||||||
when:
|
when:
|
||||||
def signer = new ResponseSignerFactory(conf).getObject()
|
def signer = new ResponseSignerFactory(conf).createSigner()
|
||||||
then:
|
then:
|
||||||
signer instanceof NoSigner
|
signer instanceof NoSigner
|
||||||
}
|
}
|
||||||
@@ -20,7 +20,7 @@ class ResponseSignerFactorySpec extends Specification {
|
|||||||
setup:
|
setup:
|
||||||
def conf = new SignatureConfig()
|
def conf = new SignatureConfig()
|
||||||
when:
|
when:
|
||||||
def signer = new ResponseSignerFactory(conf).getObject()
|
def signer = new ResponseSignerFactory(conf).createSigner()
|
||||||
then:
|
then:
|
||||||
signer instanceof NoSigner
|
signer instanceof NoSigner
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,11 +13,9 @@ import io.emeraldpay.dshackle.upstream.Selector
|
|||||||
import io.grpc.BindableService
|
import io.grpc.BindableService
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.mockito.Mockito.mock
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
import org.springframework.boot.test.context.SpringBootTest
|
import org.springframework.boot.test.context.SpringBootTest
|
||||||
import org.springframework.boot.test.context.TestConfiguration
|
import org.springframework.boot.test.context.TestConfiguration
|
||||||
import org.springframework.cloud.sleuth.Tracer
|
|
||||||
import org.springframework.context.annotation.Bean
|
import org.springframework.context.annotation.Bean
|
||||||
import org.springframework.context.annotation.Import
|
import org.springframework.context.annotation.Import
|
||||||
import org.springframework.context.annotation.Profile
|
import org.springframework.context.annotation.Profile
|
||||||
@@ -57,7 +55,6 @@ class IntegrationTest {
|
|||||||
fun testUpstreamTxMethodQuorumAndReader() {
|
fun testUpstreamTxMethodQuorumAndReader() {
|
||||||
val ms = multistreamHolder.getUpstream(Chain.ETHEREUM__MAINNET)
|
val ms = multistreamHolder.getUpstream(Chain.ETHEREUM__MAINNET)
|
||||||
val ethUpstream = ms.getUpstreams()[0]
|
val ethUpstream = ms.getUpstreams()[0]
|
||||||
val tracer = mock<Tracer>()
|
|
||||||
val reqReader = RequestReaderFactory.default()
|
val reqReader = RequestReaderFactory.default()
|
||||||
|
|
||||||
val txQuorum = ethUpstream.getMethods().createQuorumFor("eth_sendRawTransaction")
|
val txQuorum = ethUpstream.getMethods().createQuorumFor("eth_sendRawTransaction")
|
||||||
@@ -69,7 +66,6 @@ class IntegrationTest {
|
|||||||
Selector.UpstreamFilter.default,
|
Selector.UpstreamFilter.default,
|
||||||
txQuorum,
|
txQuorum,
|
||||||
null,
|
null,
|
||||||
tracer,
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
val txCountReader = reqReader.create(
|
val txCountReader = reqReader.create(
|
||||||
@@ -78,7 +74,6 @@ class IntegrationTest {
|
|||||||
Selector.UpstreamFilter.default,
|
Selector.UpstreamFilter.default,
|
||||||
txCountQuorum,
|
txCountQuorum,
|
||||||
null,
|
null,
|
||||||
tracer,
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ import org.mockito.kotlin.mock
|
|||||||
import org.mockito.kotlin.never
|
import org.mockito.kotlin.never
|
||||||
import org.mockito.kotlin.verify
|
import org.mockito.kotlin.verify
|
||||||
import org.mockito.kotlin.whenever
|
import org.mockito.kotlin.whenever
|
||||||
import org.springframework.cloud.sleuth.Tracer
|
|
||||||
import org.springframework.util.ResourceUtils
|
import org.springframework.util.ResourceUtils
|
||||||
import reactor.core.publisher.Flux
|
import reactor.core.publisher.Flux
|
||||||
import reactor.core.scheduler.Schedulers
|
import reactor.core.scheduler.Schedulers
|
||||||
@@ -194,7 +193,7 @@ class ReloadConfigTest {
|
|||||||
ArrayList(),
|
ArrayList(),
|
||||||
Caches.default(),
|
Caches.default(),
|
||||||
Schedulers.boundedElastic(),
|
Schedulers.boundedElastic(),
|
||||||
cs.makeCachingReaderBuilder(mock<Tracer>()),
|
cs.makeCachingReaderBuilder(),
|
||||||
cs::localReaderBuilder,
|
cs::localReaderBuilder,
|
||||||
cs.subscriptionBuilder(Schedulers.boundedElastic()),
|
cs.subscriptionBuilder(Schedulers.boundedElastic()),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import org.junit.jupiter.params.ParameterizedTest
|
|||||||
import org.junit.jupiter.params.provider.Arguments
|
import org.junit.jupiter.params.provider.Arguments
|
||||||
import org.junit.jupiter.params.provider.MethodSource
|
import org.junit.jupiter.params.provider.MethodSource
|
||||||
import org.mockito.kotlin.mock
|
import org.mockito.kotlin.mock
|
||||||
import org.springframework.cloud.sleuth.Tracer
|
|
||||||
|
|
||||||
class RequestReaderFactoryTest {
|
class RequestReaderFactoryTest {
|
||||||
private val defaultFactory = RequestReaderFactory.Default()
|
private val defaultFactory = RequestReaderFactory.Default()
|
||||||
@@ -26,7 +25,6 @@ class RequestReaderFactoryTest {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val ms = mock<Multistream>()
|
private val ms = mock<Multistream>()
|
||||||
private val tracer = mock<Tracer>()
|
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun data(): List<Arguments> {
|
fun data(): List<Arguments> {
|
||||||
@@ -37,7 +35,6 @@ class RequestReaderFactoryTest {
|
|||||||
Selector.UpstreamFilter(Selector.empty),
|
Selector.UpstreamFilter(Selector.empty),
|
||||||
MaximumValueQuorum(),
|
MaximumValueQuorum(),
|
||||||
null,
|
null,
|
||||||
tracer,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Arguments.of(
|
Arguments.of(
|
||||||
@@ -46,7 +43,6 @@ class RequestReaderFactoryTest {
|
|||||||
Selector.UpstreamFilter(Selector.empty),
|
Selector.UpstreamFilter(Selector.empty),
|
||||||
BroadcastQuorum(),
|
BroadcastQuorum(),
|
||||||
null,
|
null,
|
||||||
tracer,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import org.junit.jupiter.api.Test
|
|||||||
import org.mockito.kotlin.doReturn
|
import org.mockito.kotlin.doReturn
|
||||||
import org.mockito.kotlin.mock
|
import org.mockito.kotlin.mock
|
||||||
import org.mockito.kotlin.spy
|
import org.mockito.kotlin.spy
|
||||||
import org.springframework.cloud.sleuth.Tracer
|
|
||||||
import reactor.core.publisher.Flux
|
import reactor.core.publisher.Flux
|
||||||
import reactor.core.publisher.Mono
|
import reactor.core.publisher.Mono
|
||||||
import reactor.test.StepVerifier
|
import reactor.test.StepVerifier
|
||||||
@@ -29,7 +28,6 @@ class NativeCallTest {
|
|||||||
mock<MultistreamHolder>(),
|
mock<MultistreamHolder>(),
|
||||||
mock<ResponseSigner>(),
|
mock<ResponseSigner>(),
|
||||||
MainConfig(),
|
MainConfig(),
|
||||||
mock<Tracer>(),
|
|
||||||
),
|
),
|
||||||
) {
|
) {
|
||||||
on { nativeCallResult(request) } doReturn Flux.just(
|
on { nativeCallResult(request) } doReturn Flux.just(
|
||||||
@@ -59,7 +57,6 @@ class NativeCallTest {
|
|||||||
mock<MultistreamHolder>(),
|
mock<MultistreamHolder>(),
|
||||||
mock<ResponseSigner>(),
|
mock<ResponseSigner>(),
|
||||||
MainConfig(),
|
MainConfig(),
|
||||||
mock<Tracer>(),
|
|
||||||
),
|
),
|
||||||
) {
|
) {
|
||||||
on { nativeCallResult(request) } doReturn Flux.just(
|
on { nativeCallResult(request) } doReturn Flux.just(
|
||||||
@@ -95,7 +92,6 @@ class NativeCallTest {
|
|||||||
mock<MultistreamHolder>(),
|
mock<MultistreamHolder>(),
|
||||||
mock<ResponseSigner>(),
|
mock<ResponseSigner>(),
|
||||||
MainConfig(),
|
MainConfig(),
|
||||||
mock<Tracer>(),
|
|
||||||
),
|
),
|
||||||
) {
|
) {
|
||||||
on { nativeCallResult(request) } doReturn Flux.just(
|
on { nativeCallResult(request) } doReturn Flux.just(
|
||||||
|
|||||||
Reference in New Issue
Block a user