Return upstreamId from direct reader (#257)
This commit is contained in:
@@ -48,7 +48,6 @@ import io.emeraldpay.dshackle.upstream.ethereum.EthereumPosMultiStream
|
|||||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcError
|
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcError
|
||||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcException
|
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcException
|
||||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
||||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
|
|
||||||
import io.emeraldpay.dshackle.upstream.signature.ResponseSigner
|
import io.emeraldpay.dshackle.upstream.signature.ResponseSigner
|
||||||
import io.emeraldpay.etherjar.rpc.RpcException
|
import io.emeraldpay.etherjar.rpc.RpcException
|
||||||
import io.emeraldpay.etherjar.rpc.RpcResponseError
|
import io.emeraldpay.etherjar.rpc.RpcResponseError
|
||||||
@@ -369,13 +368,14 @@ open class NativeCall(
|
|||||||
.flatMap { api ->
|
.flatMap { api ->
|
||||||
SpannedReader(api, tracer, LOCAL_READER)
|
SpannedReader(api, tracer, LOCAL_READER)
|
||||||
.read(JsonRpcRequest(ctx.payload.method, ctx.payload.params, ctx.nonce, ctx.forwardedSelector))
|
.read(JsonRpcRequest(ctx.payload.method, ctx.payload.params, ctx.nonce, ctx.forwardedSelector))
|
||||||
.flatMap(JsonRpcResponse::requireResult)
|
|
||||||
.map {
|
.map {
|
||||||
validateResult(it, "local", ctx)
|
val result = it.getResult()
|
||||||
|
val upstreamId = it.providedUpstreamId ?: ctx.upstream.getId()
|
||||||
|
validateResult(result, "local", ctx)
|
||||||
if (ctx.nonce != null) {
|
if (ctx.nonce != null) {
|
||||||
CallResult.ok(ctx.id, ctx.nonce, it, signer.sign(ctx.nonce, it, ctx.upstream.getId()), ctx.upstream.getId(), ctx)
|
CallResult.ok(ctx.id, ctx.nonce, result, signer.sign(ctx.nonce, result, upstreamId), upstreamId, ctx)
|
||||||
} else {
|
} else {
|
||||||
CallResult.ok(ctx.id, null, it, null, ctx.upstream.getId(), ctx)
|
CallResult.ok(ctx.id, null, result, null, upstreamId, ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.switchIfEmpty(
|
}.switchIfEmpty(
|
||||||
|
|||||||
@@ -121,6 +121,7 @@ class TrackEthereumAddress(
|
|||||||
.balance()
|
.balance()
|
||||||
.read(addr.address)
|
.read(addr.address)
|
||||||
.timeout(Defaults.timeout)
|
.timeout(Defaults.timeout)
|
||||||
|
.map { it.data }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildResponse(address: TrackedAddress): BlockchainOuterClass.AddressBalance {
|
private fun buildResponse(address: TrackedAddress): BlockchainOuterClass.AddressBalance {
|
||||||
|
|||||||
@@ -19,16 +19,13 @@ import com.fasterxml.jackson.databind.ObjectMapper
|
|||||||
import io.emeraldpay.dshackle.Global
|
import io.emeraldpay.dshackle.Global
|
||||||
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.cache.HeightByHashAdding
|
|
||||||
import io.emeraldpay.dshackle.commons.CACHE_BLOCK_BY_HASH_READER
|
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_BLOCK_BY_HEIGHT_READER
|
||||||
import io.emeraldpay.dshackle.commons.CACHE_HEIGHT_BY_HASH_READER
|
|
||||||
import io.emeraldpay.dshackle.commons.CACHE_RECEIPTS_READER
|
import io.emeraldpay.dshackle.commons.CACHE_RECEIPTS_READER
|
||||||
import io.emeraldpay.dshackle.commons.CACHE_TX_BY_HASH_READER
|
import io.emeraldpay.dshackle.commons.CACHE_TX_BY_HASH_READER
|
||||||
import io.emeraldpay.dshackle.commons.DIRECT_QUORUM_RPC_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.SourceContainer
|
|
||||||
import io.emeraldpay.dshackle.data.TxContainer
|
import io.emeraldpay.dshackle.data.TxContainer
|
||||||
import io.emeraldpay.dshackle.data.TxId
|
import io.emeraldpay.dshackle.data.TxId
|
||||||
import io.emeraldpay.dshackle.reader.CompoundReader
|
import io.emeraldpay.dshackle.reader.CompoundReader
|
||||||
@@ -39,6 +36,7 @@ import io.emeraldpay.dshackle.reader.TransformingReader
|
|||||||
import io.emeraldpay.dshackle.upstream.Lifecycle
|
import io.emeraldpay.dshackle.upstream.Lifecycle
|
||||||
import io.emeraldpay.dshackle.upstream.Multistream
|
import io.emeraldpay.dshackle.upstream.Multistream
|
||||||
import io.emeraldpay.dshackle.upstream.calls.CallMethods
|
import io.emeraldpay.dshackle.upstream.calls.CallMethods
|
||||||
|
import io.emeraldpay.dshackle.upstream.ethereum.EthereumDirectReader.Result
|
||||||
import io.emeraldpay.dshackle.upstream.ethereum.json.BlockJson
|
import io.emeraldpay.dshackle.upstream.ethereum.json.BlockJson
|
||||||
import io.emeraldpay.dshackle.upstream.ethereum.json.TransactionJsonSnapshot
|
import io.emeraldpay.dshackle.upstream.ethereum.json.TransactionJsonSnapshot
|
||||||
import io.emeraldpay.etherjar.domain.Address
|
import io.emeraldpay.etherjar.domain.Address
|
||||||
@@ -47,8 +45,8 @@ import io.emeraldpay.etherjar.domain.TransactionId
|
|||||||
import io.emeraldpay.etherjar.domain.Wei
|
import io.emeraldpay.etherjar.domain.Wei
|
||||||
import io.emeraldpay.etherjar.rpc.json.TransactionRefJson
|
import io.emeraldpay.etherjar.rpc.json.TransactionRefJson
|
||||||
import org.apache.commons.collections4.Factory
|
import org.apache.commons.collections4.Factory
|
||||||
import org.slf4j.LoggerFactory
|
|
||||||
import org.springframework.cloud.sleuth.Tracer
|
import org.springframework.cloud.sleuth.Tracer
|
||||||
|
import reactor.core.publisher.Mono
|
||||||
import java.util.function.Function
|
import java.util.function.Function
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -57,19 +55,16 @@ import java.util.function.Function
|
|||||||
open class EthereumCachingReader(
|
open class EthereumCachingReader(
|
||||||
private val up: Multistream,
|
private val up: Multistream,
|
||||||
private val caches: Caches,
|
private val caches: Caches,
|
||||||
private val callMethodsFactory: Factory<CallMethods>,
|
callMethodsFactory: Factory<CallMethods>,
|
||||||
private val tracer: Tracer
|
private val tracer: Tracer
|
||||||
) : Lifecycle {
|
) : Lifecycle {
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val log = LoggerFactory.getLogger(EthereumCachingReader::class.java)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val objectMapper: ObjectMapper = Global.objectMapper
|
private val objectMapper: ObjectMapper = Global.objectMapper
|
||||||
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, tracer)
|
||||||
|
|
||||||
val extractBlock = Function<BlockContainer, BlockJson<TransactionRefJson>> { block ->
|
private val extractBlock = Function<Result<BlockContainer>, BlockJson<TransactionRefJson>> { result ->
|
||||||
|
val block = result.data
|
||||||
val existing = block.getParsed(BlockJson::class.java)
|
val existing = block.getParsed(BlockJson::class.java)
|
||||||
if (existing != null) {
|
if (existing != null) {
|
||||||
existing.withoutTransactionDetails()
|
existing.withoutTransactionDetails()
|
||||||
@@ -80,12 +75,9 @@ open class EthereumCachingReader(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val extractTx = Function<TxContainer, TransactionJsonSnapshot> { tx ->
|
private val extractTx = Function<Result<TxContainer>, TransactionJsonSnapshot> { result ->
|
||||||
tx.getParsed(TransactionJsonSnapshot::class.java) ?: objectMapper.readValue(tx.json, TransactionJsonSnapshot::class.java)
|
result.data.getParsed(TransactionJsonSnapshot::class.java)
|
||||||
}
|
?: objectMapper.readValue(result.data.json, TransactionJsonSnapshot::class.java)
|
||||||
|
|
||||||
val asRaw = Function<SourceContainer, ByteArray> { tx ->
|
|
||||||
tx.json ?: ByteArray(0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val idToBlockHash = Function<BlockId, BlockHash> { id -> BlockHash.from(id.value) }
|
private val idToBlockHash = Function<BlockId, BlockHash> { id -> BlockHash.from(id.value) }
|
||||||
@@ -95,16 +87,13 @@ open class EthereumCachingReader(
|
|||||||
private val idToTxHash = Function<TxId, TransactionId> { id -> TransactionId.from(id.value) }
|
private val idToTxHash = Function<TxId, TransactionId> { id -> TransactionId.from(id.value) }
|
||||||
|
|
||||||
private val blocksByIdAsCont = CompoundReader(
|
private val blocksByIdAsCont = CompoundReader(
|
||||||
SpannedReader(caches.getBlocksByHash(), tracer, CACHE_BLOCK_BY_HASH_READER),
|
SpannedReader(CacheWithUpstreamIdReader(caches.getBlocksByHash()), tracer, CACHE_BLOCK_BY_HASH_READER),
|
||||||
SpannedReader(RekeyingReader(idToBlockHash, directReader.blockReader), tracer, DIRECT_QUORUM_RPC_READER)
|
SpannedReader(RekeyingReader(idToBlockHash, directReader.blockReader), tracer, DIRECT_QUORUM_RPC_READER)
|
||||||
)
|
)
|
||||||
|
|
||||||
private val heightByHash =
|
fun blocksByHashAsCont(): Reader<BlockHash, Result<BlockContainer>> {
|
||||||
SpannedReader(HeightByHashAdding(caches, blocksByIdAsCont), tracer, CACHE_HEIGHT_BY_HASH_READER)
|
|
||||||
|
|
||||||
fun blocksByHashAsCont(): Reader<BlockHash, BlockContainer> {
|
|
||||||
return CompoundReader(
|
return CompoundReader(
|
||||||
SpannedReader(RekeyingReader(blockHashToId, caches.getBlocksByHash()), tracer, CACHE_BLOCK_BY_HASH_READER),
|
SpannedReader(CacheWithUpstreamIdReader(RekeyingReader(blockHashToId, caches.getBlocksByHash())), tracer, CACHE_BLOCK_BY_HASH_READER),
|
||||||
SpannedReader(directReader.blockReader, tracer, DIRECT_QUORUM_RPC_READER)
|
SpannedReader(directReader.blockReader, tracer, DIRECT_QUORUM_RPC_READER)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -116,20 +105,13 @@ open class EthereumCachingReader(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun blocksByIdParsed(): Reader<BlockId, BlockJson<TransactionRefJson>> {
|
open fun blocksByIdAsCont(): Reader<BlockId, Result<BlockContainer>> {
|
||||||
return TransformingReader(
|
|
||||||
blocksByIdAsCont(),
|
|
||||||
extractBlock
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun blocksByIdAsCont(): Reader<BlockId, BlockContainer> {
|
|
||||||
return blocksByIdAsCont
|
return blocksByIdAsCont
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun blocksByHeightAsCont(): Reader<Long, BlockContainer> {
|
open fun blocksByHeightAsCont(): Reader<Long, Result<BlockContainer>> {
|
||||||
return CompoundReader(
|
return CompoundReader(
|
||||||
SpannedReader(caches.getBlocksByHeight(), tracer, CACHE_BLOCK_BY_HEIGHT_READER),
|
SpannedReader(CacheWithUpstreamIdReader(caches.getBlocksByHeight()), tracer, CACHE_BLOCK_BY_HEIGHT_READER),
|
||||||
SpannedReader(directReader.blockByHeightReader, tracer, DIRECT_QUORUM_RPC_READER)
|
SpannedReader(directReader.blockByHeightReader, tracer, DIRECT_QUORUM_RPC_READER)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -144,42 +126,38 @@ open class EthereumCachingReader(
|
|||||||
open fun txByHash(): Reader<TransactionId, TransactionJsonSnapshot> {
|
open fun txByHash(): Reader<TransactionId, TransactionJsonSnapshot> {
|
||||||
return TransformingReader(
|
return TransformingReader(
|
||||||
CompoundReader(
|
CompoundReader(
|
||||||
RekeyingReader(txHashToId, caches.getTxByHash()),
|
CacheWithUpstreamIdReader(RekeyingReader(txHashToId, caches.getTxByHash())),
|
||||||
directReader.txReader
|
directReader.txReader
|
||||||
),
|
),
|
||||||
extractTx
|
extractTx
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun txByHashAsCont(): Reader<TxId, TxContainer> {
|
open fun txByHashAsCont(): Reader<TxId, Result<TxContainer>> {
|
||||||
return CompoundReader(
|
return CompoundReader(
|
||||||
SpannedReader(caches.getTxByHash(), tracer, CACHE_TX_BY_HASH_READER),
|
CacheWithUpstreamIdReader(SpannedReader(caches.getTxByHash(), tracer, CACHE_TX_BY_HASH_READER)),
|
||||||
SpannedReader(RekeyingReader(idToTxHash, directReader.txReader), tracer, DIRECT_QUORUM_RPC_READER)
|
SpannedReader(RekeyingReader(idToTxHash, directReader.txReader), tracer, DIRECT_QUORUM_RPC_READER)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun balance(): Reader<Address, Wei> {
|
fun balance(): Reader<Address, Result<Wei>> {
|
||||||
// TODO include height as part of cache?
|
// TODO include height as part of cache?
|
||||||
return CompoundReader(
|
return CompoundReader(
|
||||||
balanceCache, directReader.balanceReader
|
CacheWithUpstreamIdReader(balanceCache), directReader.balanceReader
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun receipts(): Reader<TxId, ByteArray> {
|
fun receipts(): Reader<TxId, Result<ByteArray>> {
|
||||||
val requested = RekeyingReader(
|
val requested = RekeyingReader(
|
||||||
{ txid: TxId -> TransactionId.from(txid.value) },
|
{ txid: TxId -> TransactionId.from(txid.value) },
|
||||||
directReader.receiptReader
|
directReader.receiptReader
|
||||||
)
|
)
|
||||||
return CompoundReader(
|
return CompoundReader(
|
||||||
SpannedReader(caches.getReceipts(), tracer, CACHE_RECEIPTS_READER),
|
CacheWithUpstreamIdReader(SpannedReader(caches.getReceipts(), tracer, CACHE_RECEIPTS_READER)),
|
||||||
SpannedReader(requested, tracer, DIRECT_QUORUM_RPC_READER)
|
SpannedReader(requested, tracer, DIRECT_QUORUM_RPC_READER)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun heightByHash(): Reader<BlockId, Long> {
|
|
||||||
return heightByHash
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isRunning(): Boolean {
|
override fun isRunning(): Boolean {
|
||||||
// TODO should be always running?
|
// TODO should be always running?
|
||||||
return true // up.isRunning
|
return true // up.isRunning
|
||||||
@@ -194,4 +172,13 @@ open class EthereumCachingReader(
|
|||||||
|
|
||||||
override fun stop() {
|
override fun stop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class CacheWithUpstreamIdReader<K, D>(
|
||||||
|
private val reader: Reader<K, D>
|
||||||
|
) : Reader<K, Result<D>> {
|
||||||
|
override fun read(key: K): Mono<Result<D>> {
|
||||||
|
return reader.read(key)
|
||||||
|
.map { Result(it, null) }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,74 +53,79 @@ class EthereumDirectReader(
|
|||||||
private val objectMapper: ObjectMapper = Global.objectMapper
|
private val objectMapper: ObjectMapper = Global.objectMapper
|
||||||
var quorumReaderFactory: QuorumReaderFactory = QuorumReaderFactory.default()
|
var quorumReaderFactory: QuorumReaderFactory = QuorumReaderFactory.default()
|
||||||
|
|
||||||
val blockReader: Reader<BlockHash, BlockContainer>
|
val blockReader: Reader<BlockHash, Result<BlockContainer>>
|
||||||
val blockByHeightReader: Reader<Long, BlockContainer>
|
val blockByHeightReader: Reader<Long, Result<BlockContainer>>
|
||||||
val txReader: Reader<TransactionId, TxContainer>
|
val txReader: Reader<TransactionId, Result<TxContainer>>
|
||||||
val balanceReader: Reader<Address, Wei>
|
val balanceReader: Reader<Address, Result<Wei>>
|
||||||
val receiptReader: Reader<TransactionId, ByteArray>
|
val receiptReader: Reader<TransactionId, Result<ByteArray>>
|
||||||
|
|
||||||
init {
|
init {
|
||||||
blockReader = object : Reader<BlockHash, BlockContainer> {
|
blockReader = object : Reader<BlockHash, Result<BlockContainer>> {
|
||||||
override fun read(key: BlockHash): Mono<BlockContainer> {
|
override fun read(key: BlockHash): Mono<Result<BlockContainer>> {
|
||||||
val request = JsonRpcRequest("eth_getBlockByHash", listOf(key.toHex(), false))
|
val request = JsonRpcRequest("eth_getBlockByHash", listOf(key.toHex(), false))
|
||||||
return readBlock(request, key.toHex())
|
return readBlock(request, key.toHex())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
blockByHeightReader = object : Reader<Long, BlockContainer> {
|
blockByHeightReader = object : Reader<Long, Result<BlockContainer>> {
|
||||||
override fun read(key: Long): Mono<BlockContainer> {
|
override fun read(key: Long): Mono<Result<BlockContainer>> {
|
||||||
val heightMatcher = Selector.HeightMatcher(key)
|
val heightMatcher = Selector.HeightMatcher(key)
|
||||||
val request = JsonRpcRequest("eth_getBlockByNumber", listOf(HexQuantity.from(key).toHex(), false))
|
val request = JsonRpcRequest("eth_getBlockByNumber", listOf(HexQuantity.from(key).toHex(), false))
|
||||||
return readBlock(request, key.toString(), heightMatcher)
|
return readBlock(request, key.toString(), heightMatcher)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
txReader = object : Reader<TransactionId, TxContainer> {
|
txReader = object : Reader<TransactionId, Result<TxContainer>> {
|
||||||
override fun read(key: TransactionId): Mono<TxContainer> {
|
override fun read(key: TransactionId): Mono<Result<TxContainer>> {
|
||||||
val request = JsonRpcRequest("eth_getTransactionByHash", listOf(key.toHex()))
|
val request = JsonRpcRequest("eth_getTransactionByHash", listOf(key.toHex()))
|
||||||
return readWithQuorum(request) // retries were removed because we use NotNullQuorum which handle errors too
|
return readWithQuorum(request) // retries were removed because we use NotNullQuorum which handle errors too
|
||||||
.timeout(Defaults.timeoutInternal, Mono.error(TimeoutException("Tx not read $key")))
|
.timeout(Defaults.timeoutInternal, Mono.error(TimeoutException("Tx not read $key")))
|
||||||
.flatMap { txbytes ->
|
.flatMap { result ->
|
||||||
val tx = objectMapper.readValue(txbytes, TransactionJsonSnapshot::class.java)
|
val tx = objectMapper.readValue(result.data, TransactionJsonSnapshot::class.java)
|
||||||
if (tx == null) {
|
if (tx == null) {
|
||||||
Mono.empty()
|
Mono.empty()
|
||||||
} else {
|
} else {
|
||||||
Mono.just(TxContainer.from(tx, txbytes))
|
Mono.just(
|
||||||
|
Result(TxContainer.from(tx, result.data), result.upstreamId)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.doOnNext { tx ->
|
.doOnNext { tx ->
|
||||||
if (tx.blockId != null) {
|
if (tx.data.blockId != null) {
|
||||||
caches.cache(Caches.Tag.REQUESTED, tx)
|
caches.cache(Caches.Tag.REQUESTED, tx.data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
balanceReader = object : Reader<Address, Wei> {
|
balanceReader = object : Reader<Address, Result<Wei>> {
|
||||||
override fun read(key: Address): Mono<Wei> {
|
override fun read(key: Address): Mono<Result<Wei>> {
|
||||||
val height = up.getHead().getCurrentHeight()?.let { HexQuantity.from(it).toHex() } ?: "latest"
|
val height = up.getHead().getCurrentHeight()?.let { HexQuantity.from(it).toHex() } ?: "latest"
|
||||||
val request = JsonRpcRequest("eth_getBalance", listOf(key.toHex(), height))
|
val request = JsonRpcRequest("eth_getBalance", listOf(key.toHex(), height))
|
||||||
return readWithQuorum(request)
|
return readWithQuorum(request)
|
||||||
.timeout(Defaults.timeoutInternal, Mono.error(TimeoutException("Balance not read $key")))
|
.timeout(Defaults.timeoutInternal, Mono.error(TimeoutException("Balance not read $key")))
|
||||||
.map {
|
.map {
|
||||||
val str = String(it)
|
val str = String(it.data)
|
||||||
// it's a json string, i.e. wrapped with quotes, ex. _"0x1234"_
|
// it's a json string, i.e. wrapped with quotes, ex. _"0x1234"_
|
||||||
if (str.startsWith("\"") && str.endsWith("\"")) {
|
if (str.startsWith("\"") && str.endsWith("\"")) {
|
||||||
Wei.from(str.substring(1, str.length - 1))
|
Result(
|
||||||
|
Wei.from(str.substring(1, str.length - 1)),
|
||||||
|
it.upstreamId
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
throw RpcException(RpcResponseError.CODE_UPSTREAM_INVALID_RESPONSE, "Not Wei value")
|
throw RpcException(RpcResponseError.CODE_UPSTREAM_INVALID_RESPONSE, "Not Wei value")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.retryWhen(Retry.fixedDelay(3, Duration.ofMillis(200)))
|
.retryWhen(Retry.fixedDelay(3, Duration.ofMillis(200)))
|
||||||
.doOnNext { value ->
|
.doOnNext { value ->
|
||||||
balanceCache.put(key, value)
|
balanceCache.put(key, value.data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
receiptReader = object : Reader<TransactionId, ByteArray> {
|
receiptReader = object : Reader<TransactionId, Result<ByteArray>> {
|
||||||
override fun read(key: TransactionId): Mono<ByteArray> {
|
override fun read(key: TransactionId): Mono<Result<ByteArray>> {
|
||||||
val request = JsonRpcRequest("eth_getTransactionReceipt", listOf(key.toHex()))
|
val request = JsonRpcRequest("eth_getTransactionReceipt", listOf(key.toHex()))
|
||||||
return readWithQuorum(request)
|
return readWithQuorum(request)
|
||||||
.timeout(Defaults.timeoutInternal, Mono.error(TimeoutException("Receipt not read $key")))
|
.timeout(Defaults.timeoutInternal, Mono.error(TimeoutException("Receipt not read $key")))
|
||||||
.flatMap { json ->
|
.flatMap { result ->
|
||||||
val receipt = objectMapper.readValue(json, TransactionReceiptJson::class.java)
|
val receipt = objectMapper.readValue(result.data, TransactionReceiptJson::class.java)
|
||||||
if (receipt == null) {
|
if (receipt == null) {
|
||||||
log.debug("Empty receipt for txId $key")
|
log.debug("Empty receipt for txId $key")
|
||||||
Mono.empty()
|
Mono.empty()
|
||||||
@@ -131,11 +136,13 @@ class EthereumDirectReader(
|
|||||||
txId = TxId.from(key),
|
txId = TxId.from(key),
|
||||||
blockId = BlockId.from(receipt.blockHash),
|
blockId = BlockId.from(receipt.blockHash),
|
||||||
height = receipt.blockNumber,
|
height = receipt.blockNumber,
|
||||||
json = json,
|
json = result.data,
|
||||||
parsed = receipt
|
parsed = receipt
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
Mono.just(json)
|
Mono.just(
|
||||||
|
result
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -147,27 +154,35 @@ class EthereumDirectReader(
|
|||||||
request: JsonRpcRequest,
|
request: JsonRpcRequest,
|
||||||
id: String,
|
id: String,
|
||||||
matcher: Selector.Matcher = Selector.empty
|
matcher: Selector.Matcher = Selector.empty
|
||||||
): Mono<BlockContainer> {
|
): Mono<Result<BlockContainer>> {
|
||||||
return readWithQuorum(request, matcher)
|
return readWithQuorum(request, matcher)
|
||||||
.timeout(Defaults.timeoutInternal, Mono.error(TimeoutException("Block not read $id")))
|
.timeout(Defaults.timeoutInternal, Mono.error(TimeoutException("Block not read $id")))
|
||||||
.retryWhen(Retry.fixedDelay(3, Duration.ofMillis(200)))
|
.retryWhen(Retry.fixedDelay(3, Duration.ofMillis(200)))
|
||||||
.flatMap { blockbytes ->
|
.flatMap { result ->
|
||||||
val block = objectMapper.readValue(blockbytes, BlockJson::class.java) as BlockJson<TransactionRefJson>?
|
val block = objectMapper.readValue(result.data, BlockJson::class.java) as BlockJson<TransactionRefJson>?
|
||||||
if (block == null) {
|
if (block == null) {
|
||||||
Mono.empty<BlockContainer>()
|
Mono.empty()
|
||||||
} else {
|
} else {
|
||||||
Mono.just(BlockContainer.from(block, blockbytes, "unknown"))
|
Mono.just(
|
||||||
|
Result(
|
||||||
|
BlockContainer.from(block, result.data, "unknown"),
|
||||||
|
result.upstreamId
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.doOnNext { block ->
|
.doOnNext { block ->
|
||||||
caches.cache(Caches.Tag.REQUESTED, block)
|
caches.cache(Caches.Tag.REQUESTED, block.data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read from an Upstream applying a Quorum specific for that request
|
* Read from an Upstream applying a Quorum specific for that request
|
||||||
*/
|
*/
|
||||||
private fun readWithQuorum(request: JsonRpcRequest, matcher: Selector.Matcher = Selector.empty): Mono<ByteArray> {
|
private fun readWithQuorum(
|
||||||
|
request: JsonRpcRequest,
|
||||||
|
matcher: Selector.Matcher = Selector.empty
|
||||||
|
): Mono<Result<ByteArray>> {
|
||||||
return Mono.just(quorumReaderFactory)
|
return Mono.just(quorumReaderFactory)
|
||||||
.map {
|
.map {
|
||||||
it.create(
|
it.create(
|
||||||
@@ -185,7 +200,12 @@ class EthereumDirectReader(
|
|||||||
}.flatMap {
|
}.flatMap {
|
||||||
it.read(request)
|
it.read(request)
|
||||||
}.map {
|
}.map {
|
||||||
it.value
|
Result(it.value, it.resolvedBy?.getId())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class Result<T>(
|
||||||
|
val data: T,
|
||||||
|
val upstreamId: String?
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
|
|||||||
import io.emeraldpay.etherjar.hex.HexQuantity
|
import io.emeraldpay.etherjar.hex.HexQuantity
|
||||||
import io.emeraldpay.etherjar.rpc.RpcException
|
import io.emeraldpay.etherjar.rpc.RpcException
|
||||||
import io.emeraldpay.etherjar.rpc.RpcResponseError
|
import io.emeraldpay.etherjar.rpc.RpcResponseError
|
||||||
import org.slf4j.LoggerFactory
|
|
||||||
import reactor.core.publisher.Mono
|
import reactor.core.publisher.Mono
|
||||||
import reactor.kotlin.core.publisher.switchIfEmpty
|
import reactor.kotlin.core.publisher.switchIfEmpty
|
||||||
import java.math.BigInteger
|
import java.math.BigInteger
|
||||||
@@ -45,10 +44,6 @@ class EthereumLocalReader(
|
|||||||
private val localEnabled: Boolean
|
private val localEnabled: Boolean
|
||||||
) : JsonRpcReader {
|
) : JsonRpcReader {
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val log = LoggerFactory.getLogger(EthereumLocalReader::class.java)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun read(key: JsonRpcRequest): Mono<JsonRpcResponse> {
|
override fun read(key: JsonRpcRequest): Mono<JsonRpcResponse> {
|
||||||
if (methods.isHardcoded(key.method)) {
|
if (methods.isHardcoded(key.method)) {
|
||||||
return Mono.just(methods.executeHardcoded(key.method))
|
return Mono.just(methods.executeHardcoded(key.method))
|
||||||
@@ -66,7 +61,7 @@ class EthereumLocalReader(
|
|||||||
}
|
}
|
||||||
val common = commonRequests(key)
|
val common = commonRequests(key)
|
||||||
if (common != null) {
|
if (common != null) {
|
||||||
return common.map { JsonRpcResponse(it, null) }
|
return common.map { JsonRpcResponse(it.first, null, it.second) }
|
||||||
}
|
}
|
||||||
return Mono.empty()
|
return Mono.empty()
|
||||||
}
|
}
|
||||||
@@ -76,7 +71,7 @@ class EthereumLocalReader(
|
|||||||
* parses JSON into Map. But the purpose of further processing and caching for some of the requests we want
|
* parses JSON into Map. But the purpose of further processing and caching for some of the requests we want
|
||||||
* to have actual data types.
|
* to have actual data types.
|
||||||
*/
|
*/
|
||||||
fun commonRequests(key: JsonRpcRequest): Mono<ByteArray>? {
|
fun commonRequests(key: JsonRpcRequest): Mono<Pair<ByteArray, String?>>? {
|
||||||
val method = key.method
|
val method = key.method
|
||||||
val params = key.params
|
val params = key.params
|
||||||
return when {
|
return when {
|
||||||
@@ -92,8 +87,8 @@ class EthereumLocalReader(
|
|||||||
}
|
}
|
||||||
reader.txByHashAsCont()
|
reader.txByHashAsCont()
|
||||||
.read(hash)
|
.read(hash)
|
||||||
.map { it.json!! }
|
.map { it.data.json!! to it.upstreamId }
|
||||||
.switchIfEmpty { Mono.just(nullValue) }
|
.switchIfEmpty { Mono.just(nullValue to null) }
|
||||||
}
|
}
|
||||||
method == "eth_getBlockByHash" -> {
|
method == "eth_getBlockByHash" -> {
|
||||||
if (params.size != 2) {
|
if (params.size != 2) {
|
||||||
@@ -109,7 +104,7 @@ class EthereumLocalReader(
|
|||||||
if (withTx) {
|
if (withTx) {
|
||||||
null
|
null
|
||||||
} else {
|
} else {
|
||||||
reader.blocksByIdAsCont().read(hash).map { it.json!! }
|
reader.blocksByIdAsCont().read(hash).map { it.data.json!! to it.upstreamId }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
method == "eth_getBlockByNumber" -> {
|
method == "eth_getBlockByNumber" -> {
|
||||||
@@ -127,13 +122,14 @@ class EthereumLocalReader(
|
|||||||
}
|
}
|
||||||
reader.receipts()
|
reader.receipts()
|
||||||
.read(hash)
|
.read(hash)
|
||||||
.switchIfEmpty { Mono.just(nullValue) }
|
.map { it.data to it.upstreamId }
|
||||||
|
.switchIfEmpty { Mono.just(nullValue to null) }
|
||||||
}
|
}
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getBlockByNumber(params: List<Any?>): Mono<ByteArray>? {
|
fun getBlockByNumber(params: List<Any?>): Mono<Pair<ByteArray, String?>>? {
|
||||||
if (params.size != 2 || params[0] == null || params[1] == null) {
|
if (params.size != 2 || params[0] == null || params[1] == null) {
|
||||||
throw RpcException(RpcResponseError.CODE_INVALID_METHOD_PARAMS, "Must provide 2 parameters")
|
throw RpcException(RpcResponseError.CODE_INVALID_METHOD_PARAMS, "Must provide 2 parameters")
|
||||||
}
|
}
|
||||||
@@ -174,6 +170,6 @@ class EthereumLocalReader(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return reader.blocksByHeightAsCont()
|
return reader.blocksByHeightAsCont()
|
||||||
.read(number).map { it.json!! }
|
.read(number).map { it.data.json!! to it.upstreamId }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import io.emeraldpay.dshackle.Global
|
|||||||
import io.emeraldpay.dshackle.data.BlockId
|
import io.emeraldpay.dshackle.data.BlockId
|
||||||
import io.emeraldpay.dshackle.data.TxId
|
import io.emeraldpay.dshackle.data.TxId
|
||||||
import io.emeraldpay.dshackle.reader.Reader
|
import io.emeraldpay.dshackle.reader.Reader
|
||||||
|
import io.emeraldpay.dshackle.upstream.ethereum.EthereumDirectReader.Result
|
||||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumLikeMultistream
|
import io.emeraldpay.dshackle.upstream.ethereum.EthereumLikeMultistream
|
||||||
import io.emeraldpay.dshackle.upstream.ethereum.subscribe.json.LogMessage
|
import io.emeraldpay.dshackle.upstream.ethereum.subscribe.json.LogMessage
|
||||||
import io.emeraldpay.etherjar.hex.HexData
|
import io.emeraldpay.etherjar.hex.HexData
|
||||||
@@ -31,14 +32,15 @@ import reactor.kotlin.core.publisher.switchIfEmpty
|
|||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
class ProduceLogs(
|
class ProduceLogs(
|
||||||
private val receipts: Reader<TxId, ByteArray>
|
private val receipts: Reader<TxId, Result<ByteArray>>
|
||||||
) {
|
) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val log = LoggerFactory.getLogger(ProduceLogs::class.java)
|
private val log = LoggerFactory.getLogger(ProduceLogs::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(upstream: EthereumLikeMultistream) : this(upstream.getReader().receipts())
|
constructor(upstream: EthereumLikeMultistream) :
|
||||||
|
this(upstream.getReader().receipts())
|
||||||
|
|
||||||
private val objectMapper = Global.objectMapper
|
private val objectMapper = Global.objectMapper
|
||||||
|
|
||||||
@@ -77,6 +79,7 @@ class ProduceLogs(
|
|||||||
log.warn("Cannot find receipt for tx ${update.transactionId}")
|
log.warn("Cannot find receipt for tx ${update.transactionId}")
|
||||||
Mono.empty()
|
Mono.empty()
|
||||||
}
|
}
|
||||||
|
.map { it.data }
|
||||||
.flatMapMany { jsonBytes ->
|
.flatMapMany { jsonBytes ->
|
||||||
// receipt could be a null, like when the original block was replaced, etc.
|
// receipt could be a null, like when the original block was replaced, etc.
|
||||||
// so just skip it as Flux.empty
|
// so just skip it as Flux.empty
|
||||||
|
|||||||
@@ -35,6 +35,9 @@ class JsonRpcResponse(
|
|||||||
|
|
||||||
constructor(result: ByteArray?, error: JsonRpcError?) : this(result, error, NumberId(0))
|
constructor(result: ByteArray?, error: JsonRpcError?) : this(result, error, NumberId(0))
|
||||||
|
|
||||||
|
constructor(result: ByteArray?, error: JsonRpcError?, resolvedBy: String?) :
|
||||||
|
this(result, error, NumberId(0), null, resolvedBy)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val NULL_VALUE = "null".toByteArray()
|
private val NULL_VALUE = "null".toByteArray()
|
||||||
|
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ class EthereumDirectReaderSpec extends Specification {
|
|||||||
then:
|
then:
|
||||||
StepVerifier.create(act)
|
StepVerifier.create(act)
|
||||||
.expectNextMatches { block ->
|
.expectNextMatches { block ->
|
||||||
block.hash.toHexWithPrefix() == hash1
|
block.data.hash.toHexWithPrefix() == hash1
|
||||||
}
|
}
|
||||||
.expectComplete()
|
.expectComplete()
|
||||||
.verify(Duration.ofSeconds(1))
|
.verify(Duration.ofSeconds(1))
|
||||||
@@ -138,7 +138,7 @@ class EthereumDirectReaderSpec extends Specification {
|
|||||||
then:
|
then:
|
||||||
StepVerifier.create(act)
|
StepVerifier.create(act)
|
||||||
.expectNextMatches { block ->
|
.expectNextMatches { block ->
|
||||||
block.hash.toHexWithPrefix() == hash1
|
block.data.hash.toHexWithPrefix() == hash1
|
||||||
}
|
}
|
||||||
.expectComplete()
|
.expectComplete()
|
||||||
.verify(Duration.ofSeconds(1))
|
.verify(Duration.ofSeconds(1))
|
||||||
@@ -174,7 +174,7 @@ class EthereumDirectReaderSpec extends Specification {
|
|||||||
then:
|
then:
|
||||||
StepVerifier.create(act)
|
StepVerifier.create(act)
|
||||||
.expectNextMatches { block ->
|
.expectNextMatches { block ->
|
||||||
block.hash.toHexWithPrefix() == hash1
|
block.data.hash.toHexWithPrefix() == hash1
|
||||||
}
|
}
|
||||||
.expectComplete()
|
.expectComplete()
|
||||||
.verify(Duration.ofSeconds(1))
|
.verify(Duration.ofSeconds(1))
|
||||||
@@ -208,7 +208,7 @@ class EthereumDirectReaderSpec extends Specification {
|
|||||||
when:
|
when:
|
||||||
def act = reader.receiptReader.read(TransactionId.from(hash1))
|
def act = reader.receiptReader.read(TransactionId.from(hash1))
|
||||||
.block(Duration.ofSeconds(1))
|
.block(Duration.ofSeconds(1))
|
||||||
.with { new String(it) }
|
.with { new String(it.data) }
|
||||||
then:
|
then:
|
||||||
act == '{"blockHash":"0x40d15edaff9acdabd2a1c96fd5f683b3300aad34e7015f34def3c56ba8a7ffb5","blockNumber":"0x64","transactionHash":"0x40d15edaff9acdabd2a1c96fd5f683b3300aad34e7015f34def3c56ba8a7ffb5","logs":[]}'
|
act == '{"blockHash":"0x40d15edaff9acdabd2a1c96fd5f683b3300aad34e7015f34def3c56ba8a7ffb5","blockNumber":"0x64","transactionHash":"0x40d15edaff9acdabd2a1c96fd5f683b3300aad34e7015f34def3c56ba8a7ffb5","logs":[]}'
|
||||||
}
|
}
|
||||||
@@ -245,7 +245,7 @@ class EthereumDirectReaderSpec extends Specification {
|
|||||||
when:
|
when:
|
||||||
def act = reader.receiptReader.read(TransactionId.from(hash1))
|
def act = reader.receiptReader.read(TransactionId.from(hash1))
|
||||||
.block(Duration.ofSeconds(1))
|
.block(Duration.ofSeconds(1))
|
||||||
.with { new String(it) }
|
.with { new String(it.data) }
|
||||||
then:
|
then:
|
||||||
act == '{"blockHash":"0x40d15edaff9acdabd2a1c96fd5f683b3300aad34e7015f34def3c56ba8a7ffb5","blockNumber":"0x64","transactionHash":"0x40d15edaff9acdabd2a1c96fd5f683b3300aad34e7015f34def3c56ba8a7ffb5","logs":[]}'
|
act == '{"blockHash":"0x40d15edaff9acdabd2a1c96fd5f683b3300aad34e7015f34def3c56ba8a7ffb5","blockNumber":"0x64","transactionHash":"0x40d15edaff9acdabd2a1c96fd5f683b3300aad34e7015f34def3c56ba8a7ffb5","logs":[]}'
|
||||||
}
|
}
|
||||||
@@ -302,7 +302,7 @@ class EthereumDirectReaderSpec extends Specification {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
when:
|
when:
|
||||||
def act = reader.balanceReader.read(Address.from(address1))
|
def act = reader.balanceReader.read(Address.from(address1)).map {it.data}
|
||||||
then:
|
then:
|
||||||
StepVerifier.create(act)
|
StepVerifier.create(act)
|
||||||
.expectNext(Wei.from("0x100"))
|
.expectNext(Wei.from("0x100"))
|
||||||
@@ -334,7 +334,7 @@ class EthereumDirectReaderSpec extends Specification {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
when:
|
when:
|
||||||
def act = reader.balanceReader.read(Address.from(address1))
|
def act = reader.balanceReader.read(Address.from(address1)).map {it.data}
|
||||||
then:
|
then:
|
||||||
StepVerifier.create(act)
|
StepVerifier.create(act)
|
||||||
.expectNext(Wei.from("0x100"))
|
.expectNext(Wei.from("0x100"))
|
||||||
@@ -379,7 +379,7 @@ class EthereumDirectReaderSpec extends Specification {
|
|||||||
then:
|
then:
|
||||||
StepVerifier.create(act)
|
StepVerifier.create(act)
|
||||||
.expectNextMatches { block ->
|
.expectNextMatches { block ->
|
||||||
block.hash.toHexWithPrefix() == hash1
|
block.data.hash.toHexWithPrefix() == hash1
|
||||||
}
|
}
|
||||||
.expectComplete()
|
.expectComplete()
|
||||||
.verify(Duration.ofSeconds(1))
|
.verify(Duration.ofSeconds(1))
|
||||||
@@ -422,7 +422,7 @@ class EthereumDirectReaderSpec extends Specification {
|
|||||||
then:
|
then:
|
||||||
StepVerifier.create(act)
|
StepVerifier.create(act)
|
||||||
.expectNextMatches { block ->
|
.expectNextMatches { block ->
|
||||||
block.hash.toHexWithPrefix() == hash1
|
block.data.hash.toHexWithPrefix() == hash1
|
||||||
}
|
}
|
||||||
.expectComplete()
|
.expectComplete()
|
||||||
.verify(Duration.ofSeconds(1))
|
.verify(Duration.ofSeconds(1))
|
||||||
|
|||||||
@@ -69,7 +69,9 @@ class EthereumLocalReaderSpec extends Specification {
|
|||||||
_ * blocksByIdAsCont() >> new EmptyReader<>()
|
_ * blocksByIdAsCont() >> new EmptyReader<>()
|
||||||
_ * txByHashAsCont() >> new EmptyReader<>()
|
_ * txByHashAsCont() >> new EmptyReader<>()
|
||||||
1 * blocksByHeightAsCont() >> Mock(Reader) {
|
1 * blocksByHeightAsCont() >> Mock(Reader) {
|
||||||
1 * read(101L) >> Mono.just(TestingCommons.blockForEthereum(101L))
|
1 * read(101L) >> Mono.just(
|
||||||
|
new EthereumDirectReader.Result<>(TestingCommons.blockForEthereum(101L), null)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
def methods = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET)
|
def methods = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET)
|
||||||
@@ -81,8 +83,8 @@ class EthereumLocalReaderSpec extends Specification {
|
|||||||
then:
|
then:
|
||||||
act != null
|
act != null
|
||||||
with(act.block()) {
|
with(act.block()) {
|
||||||
it.length > 0
|
it.first.length > 0
|
||||||
with(Global.objectMapper.readValue(it, BlockJson)) {
|
with(Global.objectMapper.readValue(it.first, BlockJson)) {
|
||||||
number == 101
|
number == 101
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -95,7 +97,9 @@ class EthereumLocalReaderSpec extends Specification {
|
|||||||
_ * blocksByIdAsCont() >> new EmptyReader<>()
|
_ * blocksByIdAsCont() >> new EmptyReader<>()
|
||||||
_ * txByHashAsCont() >> new EmptyReader<>()
|
_ * txByHashAsCont() >> new EmptyReader<>()
|
||||||
1 * blocksByHeightAsCont() >> Mock(Reader) {
|
1 * blocksByHeightAsCont() >> Mock(Reader) {
|
||||||
1 * read(0L) >> Mono.just(TestingCommons.blockForEthereum(0L))
|
1 * read(0L) >> Mono.just(
|
||||||
|
new EthereumDirectReader.Result<>(TestingCommons.blockForEthereum(0L), null)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
def methods = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET)
|
def methods = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET)
|
||||||
@@ -107,8 +111,8 @@ class EthereumLocalReaderSpec extends Specification {
|
|||||||
then:
|
then:
|
||||||
act != null
|
act != null
|
||||||
with(act.block()) {
|
with(act.block()) {
|
||||||
it.length > 0
|
it.first.length > 0
|
||||||
with(Global.objectMapper.readValue(it, BlockJson)) {
|
with(Global.objectMapper.readValue(it.first, BlockJson)) {
|
||||||
number == 0
|
number == 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -121,7 +125,9 @@ class EthereumLocalReaderSpec extends Specification {
|
|||||||
_ * blocksByIdAsCont() >> new EmptyReader<>()
|
_ * blocksByIdAsCont() >> new EmptyReader<>()
|
||||||
_ * txByHashAsCont() >> new EmptyReader<>()
|
_ * txByHashAsCont() >> new EmptyReader<>()
|
||||||
1 * blocksByHeightAsCont() >> Mock(Reader) {
|
1 * blocksByHeightAsCont() >> Mock(Reader) {
|
||||||
1 * read(74735L) >> Mono.just(TestingCommons.blockForEthereum(74735L))
|
1 * read(74735L) >> Mono.just(
|
||||||
|
new EthereumDirectReader.Result<>(TestingCommons.blockForEthereum(74735L), null)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
def methods = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET)
|
def methods = new DefaultEthereumMethods(Chain.ETHEREUM__MAINNET)
|
||||||
@@ -133,8 +139,8 @@ class EthereumLocalReaderSpec extends Specification {
|
|||||||
then:
|
then:
|
||||||
act != null
|
act != null
|
||||||
with(act.block()) {
|
with(act.block()) {
|
||||||
it.length > 0
|
it.first.length > 0
|
||||||
with(Global.objectMapper.readValue(it, BlockJson)) {
|
with(Global.objectMapper.readValue(it.first, BlockJson)) {
|
||||||
number == 74735
|
number == 74735
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package io.emeraldpay.dshackle.upstream.ethereum.subscribe
|
|||||||
import io.emeraldpay.dshackle.data.BlockId
|
import io.emeraldpay.dshackle.data.BlockId
|
||||||
import io.emeraldpay.dshackle.data.TxId
|
import io.emeraldpay.dshackle.data.TxId
|
||||||
import io.emeraldpay.dshackle.reader.Reader
|
import io.emeraldpay.dshackle.reader.Reader
|
||||||
|
import io.emeraldpay.dshackle.upstream.ethereum.EthereumDirectReader
|
||||||
import reactor.core.publisher.Mono
|
import reactor.core.publisher.Mono
|
||||||
import spock.lang.Specification
|
import spock.lang.Specification
|
||||||
|
|
||||||
@@ -38,7 +39,8 @@ class ProduceLogsSpec extends Specification {
|
|||||||
' }'
|
' }'
|
||||||
|
|
||||||
def receipts = Mock(Reader) {
|
def receipts = Mock(Reader) {
|
||||||
1 * it.read(TxId.from("0x6c88df9d65ccc9351db65676c3581b29483e8dabb71c48ef7671c44b0d5568af")) >> Mono.just(receipt.getBytes())
|
1 * it.read(TxId.from("0x6c88df9d65ccc9351db65676c3581b29483e8dabb71c48ef7671c44b0d5568af")) >>
|
||||||
|
Mono.just(new EthereumDirectReader.Result<>(receipt.getBytes(), null))
|
||||||
}
|
}
|
||||||
def producer = new ProduceLogs(receipts)
|
def producer = new ProduceLogs(receipts)
|
||||||
def update = new ConnectBlockUpdates.Update(
|
def update = new ConnectBlockUpdates.Update(
|
||||||
@@ -61,7 +63,8 @@ class ProduceLogsSpec extends Specification {
|
|||||||
String receipt = 'null'
|
String receipt = 'null'
|
||||||
|
|
||||||
def receipts = Mock(Reader) {
|
def receipts = Mock(Reader) {
|
||||||
1 * it.read(TxId.from("0x6c88df9d65ccc9351db65676c3581b29483e8dabb71c48ef7671c44b0d5568af")) >> Mono.just(receipt.getBytes())
|
1 * it.read(TxId.from("0x6c88df9d65ccc9351db65676c3581b29483e8dabb71c48ef7671c44b0d5568af")) >>
|
||||||
|
Mono.just(new EthereumDirectReader.Result<>(receipt.getBytes(), null))
|
||||||
}
|
}
|
||||||
def producer = new ProduceLogs(receipts)
|
def producer = new ProduceLogs(receipts)
|
||||||
def update = new ConnectBlockUpdates.Update(
|
def update = new ConnectBlockUpdates.Update(
|
||||||
@@ -107,7 +110,8 @@ class ProduceLogsSpec extends Specification {
|
|||||||
' }'
|
' }'
|
||||||
|
|
||||||
def receipts = Mock(Reader) {
|
def receipts = Mock(Reader) {
|
||||||
1 * it.read(TxId.from("0x6c88df9d65ccc9351db65676c3581b29483e8dabb71c48ef7671c44b0d5568af")) >> Mono.just(receipt.getBytes())
|
1 * it.read(TxId.from("0x6c88df9d65ccc9351db65676c3581b29483e8dabb71c48ef7671c44b0d5568af")) >>
|
||||||
|
Mono.just(new EthereumDirectReader.Result<>(receipt.getBytes(), null))
|
||||||
}
|
}
|
||||||
def producer = new ProduceLogs(receipts)
|
def producer = new ProduceLogs(receipts)
|
||||||
def update = new ConnectBlockUpdates.Update(
|
def update = new ConnectBlockUpdates.Update(
|
||||||
@@ -153,7 +157,8 @@ class ProduceLogsSpec extends Specification {
|
|||||||
' }'
|
' }'
|
||||||
|
|
||||||
def receipts = Mock(Reader) {
|
def receipts = Mock(Reader) {
|
||||||
1 * it.read(TxId.from("0x6c88df9d65ccc9351db65676c3581b29483e8dabb71c48ef7671c44b0d5568af")) >> Mono.just(receipt.getBytes())
|
1 * it.read(TxId.from("0x6c88df9d65ccc9351db65676c3581b29483e8dabb71c48ef7671c44b0d5568af")) >>
|
||||||
|
Mono.just(new EthereumDirectReader.Result<>(receipt.getBytes(), null))
|
||||||
}
|
}
|
||||||
def producer = new ProduceLogs(receipts)
|
def producer = new ProduceLogs(receipts)
|
||||||
def update = new ConnectBlockUpdates.Update(
|
def update = new ConnectBlockUpdates.Update(
|
||||||
@@ -264,7 +269,8 @@ class ProduceLogsSpec extends Specification {
|
|||||||
' }'
|
' }'
|
||||||
|
|
||||||
def receipts = Mock(Reader) {
|
def receipts = Mock(Reader) {
|
||||||
1 * it.read(TxId.from("0xb5e554178a94fd993111f2ae64cb708cb0899d7b5182024e70d5c468164a8bec")) >> Mono.just(receipt.getBytes())
|
1 * it.read(TxId.from("0xb5e554178a94fd993111f2ae64cb708cb0899d7b5182024e70d5c468164a8bec")) >>
|
||||||
|
Mono.just(new EthereumDirectReader.Result<>(receipt.getBytes(), null))
|
||||||
}
|
}
|
||||||
def producer = new ProduceLogs(receipts)
|
def producer = new ProduceLogs(receipts)
|
||||||
def update = new ConnectBlockUpdates.Update(
|
def update = new ConnectBlockUpdates.Update(
|
||||||
@@ -343,7 +349,8 @@ class ProduceLogsSpec extends Specification {
|
|||||||
' }'
|
' }'
|
||||||
|
|
||||||
def receipts = Mock(Reader) {
|
def receipts = Mock(Reader) {
|
||||||
1 * it.read(TxId.from("0xb5e554178a94fd993111f2ae64cb708cb0899d7b5182024e70d5c468164a8bec")) >> Mono.just(receipt.getBytes())
|
1 * it.read(TxId.from("0xb5e554178a94fd993111f2ae64cb708cb0899d7b5182024e70d5c468164a8bec")) >>
|
||||||
|
Mono.just(new EthereumDirectReader.Result<>(receipt.getBytes(), null))
|
||||||
}
|
}
|
||||||
def producer = new ProduceLogs(receipts)
|
def producer = new ProduceLogs(receipts)
|
||||||
def update1 = new ConnectBlockUpdates.Update(
|
def update1 = new ConnectBlockUpdates.Update(
|
||||||
|
|||||||
Reference in New Issue
Block a user