solution: use caching for WS head

This commit is contained in:
Igor Artamonov
2020-02-23 23:07:31 -05:00
parent 81ccfef068
commit b255bed3a1
9 changed files with 165 additions and 47 deletions

View File

@@ -32,6 +32,8 @@ import org.slf4j.Logger
import org.slf4j.LoggerFactory
import reactor.core.publisher.Mono
import java.util.concurrent.Callable
class EthereumApiMock extends DirectEthereumApi {
private static final Logger log = LoggerFactory.getLogger(this)
@@ -55,26 +57,30 @@ class EthereumApiMock extends DirectEthereumApi {
@Override
Mono<byte[]> execute(int id, @NotNull String method, @NotNull List<?> params) {
def predefined = predefined.find { it.isSame(id, method, params) }
ResponseJson json = new ResponseJson<Object, Integer>(id: id)
if (predefined != null) {
if (predefined.exception != null) {
Callable<byte[]> call = {
def predefined = predefined.find { it.isSame(id, method, params) }
ResponseJson json = new ResponseJson<Object, Integer>(id: id)
if (predefined != null) {
if (predefined.exception != null) {
predefined.onCalled()
predefined.print()
throw predefined.exception
}
if (predefined.result instanceof RpcResponseError) {
json.error = predefined.result
} else {
json.result = predefined.result
}
predefined.onCalled()
predefined.print()
return Mono.error(predefined.exception)
}
if (predefined.result instanceof RpcResponseError) {
json.error = predefined.result
} else {
json.result = predefined.result
log.error("Method ${method} with ${params} is not mocked")
json.error = new RpcResponseError(-32601, "Method ${method} with ${params} is not mocked")
}
} else {
log.error("Method ${method} with ${params} is not mocked")
json.error = new RpcResponseError(-32601, "Method ${method} with ${params} is not mocked")
}
predefined.onCalled()
predefined.print()
return Mono.just(objectMapper.writeValueAsBytes(json))
byte[] result = objectMapper.writeValueAsBytes(json)
return result
} as Callable<byte[]>
return Mono.fromCallable(call)
}
def nativeCall(BlockchainOuterClass.NativeCallRequest request, StreamObserver<BlockchainOuterClass.NativeCallReplyItem> responseObserver) {

View File

@@ -0,0 +1,73 @@
package io.emeraldpay.dshackle.upstream.ethereum
import io.emeraldpay.dshackle.cache.BlocksMemCache
import io.emeraldpay.dshackle.cache.Caches
import io.emeraldpay.dshackle.cache.HeightCache
import io.emeraldpay.dshackle.test.TestingCommons
import io.infinitape.etherjar.domain.BlockHash
import io.infinitape.etherjar.rpc.ReactorRpcClient
import io.infinitape.etherjar.rpc.json.BlockJson
import io.infinitape.etherjar.rpc.json.TransactionRefJson
import io.infinitape.etherjar.rpc.ws.WebsocketClient
import reactor.core.publisher.Mono
import reactor.test.StepVerifier
import spock.lang.Specification
import java.time.Duration
import java.time.Instant
import java.time.temporal.ChronoUnit
class EthereumWsSpec extends Specification {
def "Uses cache to fetch block"() {
setup:
ReactorRpcClient rpcClient = Stub(ReactorRpcClient)
def apiMock = TestingCommons.api(rpcClient)
def ws = new EthereumWs(new URI("http://localhost"), new URI("http://localhost"), apiMock)
def blocksCache = Mock(BlocksMemCache)
def caches = Caches.newBuilder().setBlockByHash(blocksCache).build()
ws.setCaches(caches)
def block = new BlockJson<TransactionRefJson>()
block.hash = BlockHash.from("0x3ec2ebf5d0ec474d0ac6bc50d2770d8409ad76e119968e7919f85d5ec8915200")
block.timestamp = Instant.now().truncatedTo(ChronoUnit.SECONDS)
when:
ws.onNewBlock(block)
then:
1 * blocksCache.read(BlockHash.from("0x3ec2ebf5d0ec474d0ac6bc50d2770d8409ad76e119968e7919f85d5ec8915200")) >> Mono.just(block)
StepVerifier.create(ws.flux.take(1))
.expectNext(block)
.expectComplete()
.verify(Duration.ofSeconds(1))
}
def "Fetch block if cache is empty"() {
setup:
ReactorRpcClient rpcClient = Stub(ReactorRpcClient)
def apiMock = TestingCommons.api(rpcClient)
def ws = new EthereumWs(new URI("http://localhost"), new URI("http://localhost"), apiMock)
def blocksCache = Mock(BlocksMemCache)
def caches = Caches.newBuilder().setBlockByHash(blocksCache).build()
ws.setCaches(caches)
def block = new BlockJson<TransactionRefJson>()
block.hash = BlockHash.from("0x3ec2ebf5d0ec474d0ac6bc50d2770d8409ad76e119968e7919f85d5ec8915200")
block.timestamp = Instant.now().truncatedTo(ChronoUnit.SECONDS)
block.transactions = []
block.uncles = []
apiMock.answerOnce("eth_getBlockByHash", ["0x3ec2ebf5d0ec474d0ac6bc50d2770d8409ad76e119968e7919f85d5ec8915200", false], block)
when:
ws.onNewBlock(block)
then:
1 * blocksCache.read(_) >> Mono.empty()
StepVerifier.create(ws.flux.take(1))
.expectNext(block)
.expectComplete()
.verify(Duration.ofSeconds(1))
}
}