solution: Redis caching
This commit is contained in:
@@ -52,4 +52,56 @@ class BlocksRedisCacheSpec extends Specification {
|
||||
act == block
|
||||
}
|
||||
|
||||
def "Evict existing block"() {
|
||||
setup:
|
||||
def cache = new BlocksRedisCache(
|
||||
redis.reactive(), Chain.ETHEREUM, TestingCommons.objectMapper()
|
||||
)
|
||||
def block = new BlockJson<TransactionRefJson>()
|
||||
block.number = 100
|
||||
block.timestamp = Instant.now().minusSeconds(100).truncatedTo(ChronoUnit.SECONDS)
|
||||
block.hash = BlockHash.from(hash2)
|
||||
block.transactions = []
|
||||
block.uncles = []
|
||||
|
||||
when:
|
||||
cache.add(block).subscribe()
|
||||
def act = cache.read(BlockHash.from(hash2)).block()
|
||||
then:
|
||||
act == block
|
||||
|
||||
when:
|
||||
cache.evict(block.hash).subscribe()
|
||||
act = cache.read(BlockHash.from(hash2)).block()
|
||||
|
||||
then:
|
||||
act == null
|
||||
}
|
||||
|
||||
def "Evict non-existing block"() {
|
||||
setup:
|
||||
def cache = new BlocksRedisCache(
|
||||
redis.reactive(), Chain.ETHEREUM, TestingCommons.objectMapper()
|
||||
)
|
||||
def block = new BlockJson<TransactionRefJson>()
|
||||
block.number = 100
|
||||
block.timestamp = Instant.now().minusSeconds(100).truncatedTo(ChronoUnit.SECONDS)
|
||||
block.hash = BlockHash.from(hash2)
|
||||
block.transactions = []
|
||||
block.uncles = []
|
||||
|
||||
when:
|
||||
cache.add(block).subscribe()
|
||||
def act = cache.read(BlockHash.from(hash2)).block()
|
||||
then:
|
||||
act == block
|
||||
|
||||
when:
|
||||
cache.evict(BlockHash.from(hash3)).subscribe()
|
||||
act = cache.read(BlockHash.from(hash2)).block()
|
||||
|
||||
then:
|
||||
act == block
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -54,6 +54,35 @@ class TxRedisCacheSpec extends Specification {
|
||||
act == tx
|
||||
}
|
||||
|
||||
def "Evict single tx"() {
|
||||
setup:
|
||||
def block = new BlockJson<TransactionRefJson>()
|
||||
block.number = 100
|
||||
block.timestamp = Instant.now().minusSeconds(100).truncatedTo(ChronoUnit.SECONDS)
|
||||
block.hash = BlockHash.from(hash2)
|
||||
block.transactions = []
|
||||
block.uncles = []
|
||||
|
||||
def tx = new TransactionJson()
|
||||
tx.hash = TransactionId.from(hash3)
|
||||
tx.blockHash = block.hash
|
||||
tx.blockNumber = block.number
|
||||
tx.value = Wei.ofEthers(1.234)
|
||||
tx.nonce = 0
|
||||
|
||||
when:
|
||||
cache.add(tx, block).subscribe()
|
||||
def act = cache.read(tx.hash).block()
|
||||
then:
|
||||
act == tx
|
||||
|
||||
when:
|
||||
cache.evict(tx.hash).subscribe()
|
||||
act = cache.read(tx.hash).block()
|
||||
then:
|
||||
act == null
|
||||
}
|
||||
|
||||
def "Evict all by block data"() {
|
||||
when:
|
||||
def block1 = new BlockJson<TransactionRefJson>()
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package io.emeraldpay.dshackle.config
|
||||
|
||||
import spock.lang.Specification
|
||||
|
||||
class EnvVariablesSpec extends Specification {
|
||||
|
||||
EnvVariables reader = new EnvVariables()
|
||||
|
||||
def "Post process for usual strings"() {
|
||||
expect:
|
||||
s == reader.postProcess(s)
|
||||
where:
|
||||
s << ["", "a", "13143", "/etc/client1.myservice.com.key", "true", "1a68f20154fc258fe4149c199ad8f281"]
|
||||
}
|
||||
|
||||
def "Post process replaces from env"() {
|
||||
setup:
|
||||
System.setProperty("id", "1")
|
||||
System.setProperty("HOME", "/home/user")
|
||||
System.setProperty("PASSWORD", "1a68f20154fc258fe4149c199ad8f281")
|
||||
expect:
|
||||
replaced == reader.postProcess(orig)
|
||||
where:
|
||||
orig | replaced
|
||||
"p_\${id}" | "p_1"
|
||||
"home: \${HOME}" | "home: /home/user"
|
||||
"\${PASSWORD}" | "1a68f20154fc258fe4149c199ad8f281"
|
||||
}
|
||||
}
|
||||
@@ -134,27 +134,6 @@ class UpstreamsConfigReaderSpec extends Specification {
|
||||
}
|
||||
}
|
||||
|
||||
def "Post process for usual strings"() {
|
||||
expect:
|
||||
s == reader.postProcess(s)
|
||||
where:
|
||||
s << ["", "a", "13143", "/etc/client1.myservice.com.key", "true", "1a68f20154fc258fe4149c199ad8f281"]
|
||||
}
|
||||
|
||||
def "Post process replaces from env"() {
|
||||
setup:
|
||||
System.setProperty("id", "1")
|
||||
System.setProperty("HOME", "/home/user")
|
||||
System.setProperty("PASSWORD", "1a68f20154fc258fe4149c199ad8f281")
|
||||
expect:
|
||||
replaced == reader.postProcess(orig)
|
||||
where:
|
||||
orig | replaced
|
||||
"p_\${id}" | "p_1"
|
||||
"home: \${HOME}" | "home: /home/user"
|
||||
"\${PASSWORD}" | "1a68f20154fc258fe4149c199ad8f281"
|
||||
}
|
||||
|
||||
def "Parse config without defaults"() {
|
||||
setup:
|
||||
def config = this.class.getClassLoader().getResourceAsStream("upstreams-no-defaults.yaml")
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
package io.emeraldpay.dshackle.reader
|
||||
|
||||
import reactor.core.publisher.Mono
|
||||
import reactor.test.StepVerifier
|
||||
import spock.lang.Specification
|
||||
|
||||
import java.time.Duration
|
||||
|
||||
class CompoundReaderSpec extends Specification {
|
||||
|
||||
def reader1 = new Reader<String, String>() {
|
||||
@Override
|
||||
Mono<String> read(String key) {
|
||||
return Mono.just("test-1").delaySubscription(Duration.ofMillis(100))
|
||||
}
|
||||
}
|
||||
def reader2 = new Reader<String, String>() {
|
||||
@Override
|
||||
Mono<String> read(String key) {
|
||||
return Mono.just("test-2").delaySubscription(Duration.ofMillis(200))
|
||||
}
|
||||
}
|
||||
def reader3 = new Reader<String, String>() {
|
||||
@Override
|
||||
Mono<String> read(String key) {
|
||||
return Mono.just("test-3").delaySubscription(Duration.ofMillis(300))
|
||||
}
|
||||
}
|
||||
|
||||
def reader1Empty = new Reader<String, String>() {
|
||||
@Override
|
||||
Mono<String> read(String key) {
|
||||
return Mono.<String>empty().delaySubscription(Duration.ofMillis(100))
|
||||
}
|
||||
}
|
||||
|
||||
def "Return empty when no readers"() {
|
||||
setup:
|
||||
def reader = new CompoundReader<String, String>()
|
||||
when:
|
||||
def act = reader.read("test")
|
||||
then:
|
||||
StepVerifier.create(act)
|
||||
.expectComplete()
|
||||
.verify(Duration.ofSeconds(1))
|
||||
}
|
||||
|
||||
def "Return first"() {
|
||||
setup:
|
||||
def reader = new CompoundReader<String, String>(reader1, reader2, reader3)
|
||||
when:
|
||||
def act = reader.read("test")
|
||||
then:
|
||||
StepVerifier.create(act)
|
||||
.expectNext("test-1")
|
||||
.expectComplete()
|
||||
.verify(Duration.ofSeconds(1))
|
||||
}
|
||||
|
||||
def "Return second"() {
|
||||
setup:
|
||||
def reader = new CompoundReader<String, String>(reader3, reader2)
|
||||
when:
|
||||
def act = reader.read("test")
|
||||
then:
|
||||
StepVerifier.create(act)
|
||||
.expectNext("test-2")
|
||||
.expectComplete()
|
||||
.verify(Duration.ofSeconds(1))
|
||||
}
|
||||
|
||||
def "Return third"() {
|
||||
setup:
|
||||
def reader = new CompoundReader<String, String>(reader3, reader2, reader1)
|
||||
when:
|
||||
def act = reader.read("test")
|
||||
then:
|
||||
StepVerifier.create(act)
|
||||
.expectNext("test-1")
|
||||
.expectComplete()
|
||||
.verify(Duration.ofSeconds(1))
|
||||
}
|
||||
|
||||
def "Ignore empty"() {
|
||||
setup:
|
||||
def reader = new CompoundReader<String, String>(reader3, reader1Empty, reader2, reader1Empty)
|
||||
when:
|
||||
def act = reader.read("test")
|
||||
then:
|
||||
StepVerifier.create(act)
|
||||
.expectNext("test-2")
|
||||
.expectComplete()
|
||||
.verify(Duration.ofSeconds(1))
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule
|
||||
import io.emeraldpay.dshackle.cache.Caches
|
||||
import io.emeraldpay.dshackle.cache.CachesFactory
|
||||
import io.emeraldpay.dshackle.upstream.AggregatedUpstream
|
||||
import io.emeraldpay.dshackle.upstream.ChainUpstreams
|
||||
import io.emeraldpay.dshackle.upstream.calls.DirectCallMethods
|
||||
@@ -28,6 +29,7 @@ import io.emeraldpay.dshackle.upstream.ethereum.EthereumUpstream
|
||||
import io.emeraldpay.grpc.Chain
|
||||
import io.infinitape.etherjar.rpc.JacksonRpcConverter
|
||||
import io.infinitape.etherjar.rpc.ReactorRpcClient
|
||||
import org.springframework.core.env.StandardEnvironment
|
||||
|
||||
import java.text.SimpleDateFormat
|
||||
|
||||
@@ -73,4 +75,8 @@ class TestingCommons {
|
||||
static AggregatedUpstream aggregatedUpstream(EthereumUpstream up) {
|
||||
return new ChainUpstreams(Chain.ETHEREUM, [up], Caches.default(), objectMapper())
|
||||
}
|
||||
|
||||
static CachesFactory emptyCaches() {
|
||||
return new CachesFactory(objectMapper(), new StandardEnvironment())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ class CurrentUpstreamsSpec extends Specification {
|
||||
|
||||
def "add upstream"() {
|
||||
setup:
|
||||
def current = new CurrentUpstreams(TestingCommons.objectMapper())
|
||||
def current = new CurrentUpstreams(TestingCommons.objectMapper(), TestingCommons.emptyCaches())
|
||||
def up = new EthereumUpstreamMock("test", Chain.ETHEREUM, TestingCommons.api(Stub(ReactorRpcClient)))
|
||||
when:
|
||||
current.update(new UpstreamChange(Chain.ETHEREUM, up, UpstreamChange.ChangeType.ADDED))
|
||||
@@ -22,7 +22,7 @@ class CurrentUpstreamsSpec extends Specification {
|
||||
|
||||
def "add multiple upstreams"() {
|
||||
setup:
|
||||
def current = new CurrentUpstreams(TestingCommons.objectMapper())
|
||||
def current = new CurrentUpstreams(TestingCommons.objectMapper(), TestingCommons.emptyCaches())
|
||||
def up1 = new EthereumUpstreamMock("test1", Chain.ETHEREUM, TestingCommons.api(Stub(ReactorRpcClient)))
|
||||
def up2 = new EthereumUpstreamMock("test2", Chain.ETHEREUM_CLASSIC, TestingCommons.api(Stub(ReactorRpcClient)))
|
||||
def up3 = new EthereumUpstreamMock("test3", Chain.ETHEREUM, TestingCommons.api(Stub(ReactorRpcClient)))
|
||||
@@ -38,7 +38,7 @@ class CurrentUpstreamsSpec extends Specification {
|
||||
|
||||
def "remove upstream"() {
|
||||
setup:
|
||||
def current = new CurrentUpstreams(TestingCommons.objectMapper())
|
||||
def current = new CurrentUpstreams(TestingCommons.objectMapper(), TestingCommons.emptyCaches())
|
||||
def up1 = new EthereumUpstreamMock("test1", Chain.ETHEREUM, TestingCommons.api(Stub(ReactorRpcClient)))
|
||||
def up2 = new EthereumUpstreamMock("test2", Chain.ETHEREUM_CLASSIC, TestingCommons.api(Stub(ReactorRpcClient)))
|
||||
def up3 = new EthereumUpstreamMock("test3", Chain.ETHEREUM, TestingCommons.api(Stub(ReactorRpcClient)))
|
||||
@@ -56,7 +56,7 @@ class CurrentUpstreamsSpec extends Specification {
|
||||
|
||||
def "available after adding"() {
|
||||
setup:
|
||||
def current = new CurrentUpstreams(TestingCommons.objectMapper())
|
||||
def current = new CurrentUpstreams(TestingCommons.objectMapper(), TestingCommons.emptyCaches())
|
||||
def up1 = new EthereumUpstreamMock("test1", Chain.ETHEREUM, TestingCommons.api(Stub(ReactorRpcClient)))
|
||||
|
||||
when:
|
||||
|
||||
15
src/test/resources/upstreams-bitcoin.yaml
Normal file
15
src/test/resources/upstreams-bitcoin.yaml
Normal file
@@ -0,0 +1,15 @@
|
||||
version: v1
|
||||
|
||||
defaultOptions:
|
||||
- chains:
|
||||
- bitcoin
|
||||
options:
|
||||
min-peers: 3
|
||||
|
||||
upstreams:
|
||||
- id: local
|
||||
chain: bitcoin
|
||||
connection:
|
||||
bitcoin:
|
||||
rpc:
|
||||
url: "http://localhost:8545"
|
||||
Reference in New Issue
Block a user