solution: refactoring, more clean class names

This commit is contained in:
Igor Artamonov
2020-05-14 00:12:38 -04:00
parent 98330b8772
commit bbc21684ae
33 changed files with 275 additions and 375 deletions

View File

@@ -81,7 +81,6 @@ dependencies {
implementation "io.infinitape:etherjar-hex:$etherjarVersion" implementation "io.infinitape:etherjar-hex:$etherjarVersion"
implementation "io.infinitape:etherjar-rpc-http:$etherjarVersion" implementation "io.infinitape:etherjar-rpc-http:$etherjarVersion"
implementation "io.infinitape:etherjar-rpc-ws:$etherjarVersion" implementation "io.infinitape:etherjar-rpc-ws:$etherjarVersion"
implementation "io.infinitape:etherjar-rpc-emerald:$etherjarVersion"
implementation "io.infinitape:etherjar-tx:$etherjarVersion" implementation "io.infinitape:etherjar-tx:$etherjarVersion"
implementation 'org.bitcoinj:bitcoinj-core:0.15.8' implementation 'org.bitcoinj:bitcoinj-core:0.15.8'

View File

@@ -29,15 +29,15 @@ import reactor.core.publisher.Mono
@Service @Service
class Describe( class Describe(
@Autowired private val upstreams: Upstreams, @Autowired private val multistreamHolder: MultistreamHolder,
@Autowired private val subscribeStatus: SubscribeStatus @Autowired private val subscribeStatus: SubscribeStatus
) { ) {
fun describe(requestMono: Mono<BlockchainOuterClass.DescribeRequest>): Mono<BlockchainOuterClass.DescribeResponse> { fun describe(requestMono: Mono<BlockchainOuterClass.DescribeRequest>): Mono<BlockchainOuterClass.DescribeResponse> {
return requestMono.map { _ -> return requestMono.map { _ ->
val resp = BlockchainOuterClass.DescribeResponse.newBuilder() val resp = BlockchainOuterClass.DescribeResponse.newBuilder()
upstreams.getAvailable().forEach { chain -> multistreamHolder.getAvailable().forEach { chain ->
upstreams.getUpstream(chain)?.let { chainUpstreams -> multistreamHolder.getUpstream(chain)?.let { chainUpstreams ->
val status = subscribeStatus.chainStatus(chain, chainUpstreams.getAll()) val status = subscribeStatus.chainStatus(chain, chainUpstreams.getAll())
val targets = chainUpstreams.getMethods().getSupportedMethods() val targets = chainUpstreams.getMethods().getSupportedMethods()
val chainDescription = BlockchainOuterClass.DescribeChain.newBuilder() val chainDescription = BlockchainOuterClass.DescribeChain.newBuilder()

View File

@@ -37,7 +37,7 @@ import java.lang.Exception
@Service @Service
open class NativeCall( open class NativeCall(
@Autowired private val upstreams: Upstreams, @Autowired private val multistreamHolder: MultistreamHolder,
@Autowired private val objectMapper: ObjectMapper @Autowired private val objectMapper: ObjectMapper
) { ) {
@@ -88,17 +88,17 @@ open class NativeCall(
return Flux.error(CallFailure(0, SilentException.UnsupportedBlockchain(request.chain.number))) return Flux.error(CallFailure(0, SilentException.UnsupportedBlockchain(request.chain.number)))
} }
if (!upstreams.isAvailable(chain)) { if (!multistreamHolder.isAvailable(chain)) {
return Flux.error(CallFailure(0, SilentException.UnsupportedBlockchain(request.chain.number))) return Flux.error(CallFailure(0, SilentException.UnsupportedBlockchain(request.chain.number)))
} }
val upstream = upstreams.getUpstream(chain) val upstream = multistreamHolder.getUpstream(chain)
?: return Flux.error(CallFailure(0, SilentException.UnsupportedBlockchain(chain))) ?: return Flux.error(CallFailure(0, SilentException.UnsupportedBlockchain(chain)))
return prepareCall(request, upstream) return prepareCall(request, upstream)
} }
fun prepareCall(request: BlockchainOuterClass.NativeCallRequest, upstream: AggregatedUpstream): Flux<CallContext<RawCallDetails>> { fun prepareCall(request: BlockchainOuterClass.NativeCallRequest, upstream: Multistream): Flux<CallContext<RawCallDetails>> {
return request.itemsList.toFlux().map { return request.itemsList.toFlux().map {
val method = it.method val method = it.method
val params = it.payload.toStringUtf8() val params = it.payload.toStringUtf8()
@@ -202,7 +202,7 @@ open class NativeCall(
} }
open class CallContext<T>(val id: Int, open class CallContext<T>(val id: Int,
val upstream: AggregatedUpstream, val upstream: Multistream,
val matcher: Selector.Matcher, val matcher: Selector.Matcher,
val callQuorum: CallQuorum, val callQuorum: CallQuorum,
val payload: T) { val payload: T) {

View File

@@ -21,10 +21,8 @@ import io.emeraldpay.api.proto.BlockchainOuterClass
import io.emeraldpay.api.proto.Common import io.emeraldpay.api.proto.Common
import io.emeraldpay.dshackle.BlockchainType import io.emeraldpay.dshackle.BlockchainType
import io.emeraldpay.dshackle.data.BlockContainer import io.emeraldpay.dshackle.data.BlockContainer
import io.emeraldpay.dshackle.upstream.Upstreams import io.emeraldpay.dshackle.upstream.MultistreamHolder
import io.emeraldpay.grpc.Chain import io.emeraldpay.grpc.Chain
import io.infinitape.etherjar.rpc.json.BlockJson
import io.infinitape.etherjar.rpc.json.TransactionRefJson
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.Service import org.springframework.stereotype.Service
@@ -33,7 +31,7 @@ import reactor.core.publisher.Mono
@Service @Service
class StreamHead( class StreamHead(
@Autowired private val upstreams: Upstreams @Autowired private val multistreamHolder: MultistreamHolder
) { ) {
private val log = LoggerFactory.getLogger(StreamHead::class.java) private val log = LoggerFactory.getLogger(StreamHead::class.java)
@@ -42,7 +40,7 @@ class StreamHead(
return requestMono.map { request -> return requestMono.map { request ->
Chain.byId(request.type.number) Chain.byId(request.type.number)
}.flatMapMany { chain -> }.flatMapMany { chain ->
val up = upstreams.getUpstream(chain) val up = multistreamHolder.getUpstream(chain)
?: return@flatMapMany Flux.error<BlockchainOuterClass.ChainHead>(Exception("Unavailable chain: $chain")) ?: return@flatMapMany Flux.error<BlockchainOuterClass.ChainHead>(Exception("Unavailable chain: $chain"))
up.getHead() up.getHead()
.getFlux() .getFlux()

View File

@@ -27,13 +27,13 @@ import reactor.core.publisher.Mono
@Service @Service
class SubscribeStatus( class SubscribeStatus(
@Autowired private val upstreams: Upstreams @Autowired private val multistreamHolder: MultistreamHolder
) { ) {
fun subscribeStatus(requestMono: Mono<BlockchainOuterClass.StatusRequest>): Flux<BlockchainOuterClass.ChainStatus> { fun subscribeStatus(requestMono: Mono<BlockchainOuterClass.StatusRequest>): Flux<BlockchainOuterClass.ChainStatus> {
return requestMono.flatMapMany { return requestMono.flatMapMany {
val ups = upstreams.getAvailable().mapNotNull { chain -> val ups = multistreamHolder.getAvailable().mapNotNull { chain ->
val chainUpstream = upstreams.getUpstream(chain) val chainUpstream = multistreamHolder.getUpstream(chain)
chainUpstream?.observeStatus()?.map { avail -> chainUpstream?.observeStatus()?.map { avail ->
ChainSubscription(chain, chainUpstream, avail) ChainSubscription(chain, chainUpstream, avail)
} }
@@ -60,6 +60,6 @@ class SubscribeStatus(
.build() .build()
} }
class ChainSubscription(val chain: Chain, val up: AggregatedUpstream, val avail: UpstreamAvailability) class ChainSubscription(val chain: Chain, val up: Multistream, val avail: UpstreamAvailability)
} }

View File

@@ -19,9 +19,8 @@ import io.emeraldpay.api.proto.BlockchainOuterClass
import io.emeraldpay.api.proto.Common import io.emeraldpay.api.proto.Common
import io.emeraldpay.dshackle.BlockchainType import io.emeraldpay.dshackle.BlockchainType
import io.emeraldpay.dshackle.SilentException import io.emeraldpay.dshackle.SilentException
import io.emeraldpay.dshackle.upstream.Upstreams import io.emeraldpay.dshackle.upstream.MultistreamHolder
import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinChainUpstreams import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinMultistream
import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinUpstream
import io.emeraldpay.grpc.Chain import io.emeraldpay.grpc.Chain
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Autowired
@@ -35,7 +34,7 @@ import kotlin.collections.HashMap
@Service @Service
class TrackBitcoinAddress( class TrackBitcoinAddress(
@Autowired private val upstreams: Upstreams @Autowired private val multistreamHolder: MultistreamHolder
) : TrackAddress { ) : TrackAddress {
companion object { companion object {
@@ -43,7 +42,7 @@ class TrackBitcoinAddress(
} }
override fun isSupported(chain: Chain): Boolean { override fun isSupported(chain: Chain): Boolean {
return BlockchainType.fromBlockchain(chain) == BlockchainType.BITCOIN && upstreams.isAvailable(chain) return BlockchainType.fromBlockchain(chain) == BlockchainType.BITCOIN && multistreamHolder.isAvailable(chain)
} }
fun allAddresses(request: BlockchainOuterClass.BalanceRequest): List<String>? { fun allAddresses(request: BlockchainOuterClass.BalanceRequest): List<String>? {
@@ -63,7 +62,7 @@ class TrackBitcoinAddress(
} }
} }
fun requestBalances(chain: Chain, api: BitcoinChainUpstreams, addresses: List<String>): Flux<AddressBalance> { fun requestBalances(chain: Chain, api: BitcoinMultistream, addresses: List<String>): Flux<AddressBalance> {
return api.getReader().listUnspent() return api.getReader().listUnspent()
.flatMapMany { unspents -> .flatMapMany { unspents ->
val result = getTotal(chain, addresses, unspents) val result = getTotal(chain, addresses, unspents)
@@ -73,7 +72,7 @@ class TrackBitcoinAddress(
override fun getBalance(request: BlockchainOuterClass.BalanceRequest): Flux<BlockchainOuterClass.AddressBalance> { override fun getBalance(request: BlockchainOuterClass.BalanceRequest): Flux<BlockchainOuterClass.AddressBalance> {
val chain = Chain.byId(request.asset.chainValue) val chain = Chain.byId(request.asset.chainValue)
val upstream = upstreams.getUpstream(chain)?.cast(BitcoinChainUpstreams::class.java) val upstream = multistreamHolder.getUpstream(chain)?.cast(BitcoinMultistream::class.java)
?: return Flux.error(SilentException.UnsupportedBlockchain(request.asset.chainValue)) ?: return Flux.error(SilentException.UnsupportedBlockchain(request.asset.chainValue))
val addresses = allAddresses(request) ?: return Flux.error(SilentException("Unsupported address")) val addresses = allAddresses(request) ?: return Flux.error(SilentException("Unsupported address"))
if (addresses.isEmpty()) { if (addresses.isEmpty()) {
@@ -119,9 +118,9 @@ class TrackBitcoinAddress(
override fun subscribe(request: BlockchainOuterClass.BalanceRequest): Flux<BlockchainOuterClass.AddressBalance> { override fun subscribe(request: BlockchainOuterClass.BalanceRequest): Flux<BlockchainOuterClass.AddressBalance> {
val chain = Chain.byId(request.asset.chainValue) val chain = Chain.byId(request.asset.chainValue)
println("up: ${upstreams.getUpstream(chain)}") println("up: ${multistreamHolder.getUpstream(chain)}")
println("up cast: ${upstreams.getUpstream(chain)?.cast(BitcoinChainUpstreams::class.java)}") println("up cast: ${multistreamHolder.getUpstream(chain)?.cast(BitcoinMultistream::class.java)}")
val upstream = upstreams.getUpstream(chain)?.cast(BitcoinChainUpstreams::class.java) val upstream = multistreamHolder.getUpstream(chain)?.cast(BitcoinMultistream::class.java)
?: return Flux.error(SilentException.UnsupportedBlockchain(request.asset.chainValue)) ?: return Flux.error(SilentException.UnsupportedBlockchain(request.asset.chainValue))
val addresses = allAddresses(request) ?: return Flux.error(SilentException("Unsupported address")) val addresses = allAddresses(request) ?: return Flux.error(SilentException("Unsupported address"))
if (addresses.isEmpty()) { if (addresses.isEmpty()) {

View File

@@ -20,9 +20,8 @@ import io.emeraldpay.api.proto.BlockchainOuterClass
import io.emeraldpay.api.proto.Common import io.emeraldpay.api.proto.Common
import io.emeraldpay.dshackle.BlockchainType import io.emeraldpay.dshackle.BlockchainType
import io.emeraldpay.dshackle.SilentException import io.emeraldpay.dshackle.SilentException
import io.emeraldpay.dshackle.upstream.Upstreams import io.emeraldpay.dshackle.upstream.MultistreamHolder
import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinChainUpstreams import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinMultistream
import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinUpstream
import io.emeraldpay.dshackle.upstream.bitcoin.ExtractBlock import io.emeraldpay.dshackle.upstream.bitcoin.ExtractBlock
import io.emeraldpay.grpc.Chain import io.emeraldpay.grpc.Chain
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
@@ -38,7 +37,7 @@ import kotlin.math.min
@Service @Service
class TrackBitcoinTx( class TrackBitcoinTx(
@Autowired private val upstreams: Upstreams @Autowired private val multistreamHolder: MultistreamHolder
) : TrackTx { ) : TrackTx {
companion object { companion object {
@@ -46,12 +45,12 @@ class TrackBitcoinTx(
} }
override fun isSupported(chain: Chain): Boolean { override fun isSupported(chain: Chain): Boolean {
return BlockchainType.fromBlockchain(chain) == BlockchainType.BITCOIN && upstreams.isAvailable(chain) return BlockchainType.fromBlockchain(chain) == BlockchainType.BITCOIN && multistreamHolder.isAvailable(chain)
} }
override fun subscribe(request: BlockchainOuterClass.TxStatusRequest): Flux<BlockchainOuterClass.TxStatus> { override fun subscribe(request: BlockchainOuterClass.TxStatusRequest): Flux<BlockchainOuterClass.TxStatus> {
val chain = Chain.byId(request.chainValue) val chain = Chain.byId(request.chainValue)
val upstream = upstreams.getUpstream(chain)?.cast(BitcoinChainUpstreams::class.java) val upstream = multistreamHolder.getUpstream(chain)?.cast(BitcoinMultistream::class.java)
?: return Flux.error(SilentException.UnsupportedBlockchain(chain)) ?: return Flux.error(SilentException.UnsupportedBlockchain(chain))
val txid = request.txId val txid = request.txId
val confirmations = max(min(1, request.confirmationLimit), 12) val confirmations = max(min(1, request.confirmationLimit), 12)
@@ -61,7 +60,7 @@ class TrackBitcoinTx(
}.map(this::asProto) }.map(this::asProto)
} }
fun subscribe(chain: Chain, upstream: BitcoinChainUpstreams, txid: String): Flux<TxStatus> { fun subscribe(chain: Chain, upstream: BitcoinMultistream, txid: String): Flux<TxStatus> {
return loadExisting(upstream, txid) return loadExisting(upstream, txid)
.flatMapMany { status -> .flatMapMany { status ->
if (status.mined) { if (status.mined) {
@@ -83,7 +82,7 @@ class TrackBitcoinTx(
} }
} }
fun continueWithMined(upstream: BitcoinChainUpstreams, status: TxStatus): Flux<TxStatus> { fun continueWithMined(upstream: BitcoinMultistream, status: TxStatus): Flux<TxStatus> {
return upstream.getReader().getBlock(status.blockHash!!) return upstream.getReader().getBlock(status.blockHash!!)
.map { block -> .map { block ->
TxStatus(status.txid, true, ExtractBlock.getHeight(block), true, status.blockHash, ExtractBlock.getTime(block), ExtractBlock.getDifficulty(block)) TxStatus(status.txid, true, ExtractBlock.getHeight(block), true, status.blockHash, ExtractBlock.getTime(block), ExtractBlock.getDifficulty(block))
@@ -92,7 +91,7 @@ class TrackBitcoinTx(
} }
} }
fun untilFound(chain: Chain, upstream: BitcoinChainUpstreams, txid: String): Flux<TxStatus> { fun untilFound(chain: Chain, upstream: BitcoinMultistream, txid: String): Flux<TxStatus> {
return Flux.interval(Duration.ofSeconds(1)) return Flux.interval(Duration.ofSeconds(1))
.take(Duration.ofMinutes(10)) .take(Duration.ofMinutes(10))
.flatMap { loadMempool(upstream, txid) } .flatMap { loadMempool(upstream, txid) }
@@ -103,20 +102,20 @@ class TrackBitcoinTx(
} }
} }
fun untilMined(upstream: BitcoinChainUpstreams, tx: TxStatus): Mono<TxStatus> { fun untilMined(upstream: BitcoinMultistream, tx: TxStatus): Mono<TxStatus> {
return upstream.getHead().getFlux().flatMap { return upstream.getHead().getFlux().flatMap {
loadExisting(upstream, tx.txid) loadExisting(upstream, tx.txid)
.filter { it.mined } .filter { it.mined }
}.single() }.single()
} }
fun withConfirmations(upstream: BitcoinChainUpstreams, tx: TxStatus): Flux<TxStatus> { fun withConfirmations(upstream: BitcoinMultistream, tx: TxStatus): Flux<TxStatus> {
return upstream.getHead().getFlux().map { return upstream.getHead().getFlux().map {
tx.withHead(it.height) tx.withHead(it.height)
} }
} }
fun loadExisting(api: BitcoinChainUpstreams, txid: String): Mono<TxStatus> { fun loadExisting(api: BitcoinMultistream, txid: String): Mono<TxStatus> {
val mined = api.getReader().getTx(txid) val mined = api.getReader().getTx(txid)
return mined.map { return mined.map {
val block = it["blockhash"] as String? val block = it["blockhash"] as String?
@@ -124,7 +123,7 @@ class TrackBitcoinTx(
} }
} }
fun loadMempool(upstream: BitcoinChainUpstreams, txid: String): Mono<TxStatus> { fun loadMempool(upstream: BitcoinMultistream, txid: String): Mono<TxStatus> {
val mempool = upstream.getReader().getMempool().get() val mempool = upstream.getReader().getMempool().get()
return mempool.map { return mempool.map {
if (it.contains(txid)) { if (it.contains(txid)) {

View File

@@ -21,8 +21,8 @@ import io.emeraldpay.api.proto.Common
import io.emeraldpay.dshackle.BlockchainType import io.emeraldpay.dshackle.BlockchainType
import io.emeraldpay.dshackle.Defaults import io.emeraldpay.dshackle.Defaults
import io.emeraldpay.dshackle.SilentException import io.emeraldpay.dshackle.SilentException
import io.emeraldpay.dshackle.upstream.Upstreams import io.emeraldpay.dshackle.upstream.MultistreamHolder
import io.emeraldpay.dshackle.upstream.ethereum.EthereumChainUpstream import io.emeraldpay.dshackle.upstream.ethereum.EthereumMultistream
import io.emeraldpay.grpc.Chain import io.emeraldpay.grpc.Chain
import io.infinitape.etherjar.domain.Address import io.infinitape.etherjar.domain.Address
import io.infinitape.etherjar.domain.Wei import io.infinitape.etherjar.domain.Wei
@@ -34,13 +34,13 @@ import reactor.core.publisher.Mono
@Service @Service
class TrackEthereumAddress( class TrackEthereumAddress(
@Autowired private val upstreams: Upstreams @Autowired private val multistreamHolder: MultistreamHolder
) : TrackAddress { ) : TrackAddress {
private val log = LoggerFactory.getLogger(TrackEthereumAddress::class.java) private val log = LoggerFactory.getLogger(TrackEthereumAddress::class.java)
override fun isSupported(chain: Chain): Boolean { override fun isSupported(chain: Chain): Boolean {
return BlockchainType.fromBlockchain(chain) == BlockchainType.ETHEREUM && upstreams.isAvailable(chain) return BlockchainType.fromBlockchain(chain) == BlockchainType.ETHEREUM && multistreamHolder.isAvailable(chain)
} }
override fun getBalance(request: BlockchainOuterClass.BalanceRequest): Flux<BlockchainOuterClass.AddressBalance> { override fun getBalance(request: BlockchainOuterClass.BalanceRequest): Flux<BlockchainOuterClass.AddressBalance> {
@@ -51,7 +51,7 @@ class TrackEthereumAddress(
override fun subscribe(request: BlockchainOuterClass.BalanceRequest): Flux<BlockchainOuterClass.AddressBalance> { override fun subscribe(request: BlockchainOuterClass.BalanceRequest): Flux<BlockchainOuterClass.AddressBalance> {
val chain = Chain.byId(request.asset.chainValue) val chain = Chain.byId(request.asset.chainValue)
val head = upstreams.getUpstream(chain)?.getHead()?.getFlux() ?: Flux.empty() val head = multistreamHolder.getUpstream(chain)?.getHead()?.getFlux() ?: Flux.empty()
val balances = initAddress(request) val balances = initAddress(request)
.flatMap { tracked -> .flatMap { tracked ->
val current = getBalance(tracked) val current = getBalance(tracked)
@@ -86,14 +86,14 @@ class TrackEthereumAddress(
} }
} }
fun getUpstream(chain: Chain): EthereumChainUpstream { fun getUpstream(chain: Chain): EthereumMultistream {
return upstreams.getUpstream(chain)?.cast(EthereumChainUpstream::class.java) return multistreamHolder.getUpstream(chain)?.cast(EthereumMultistream::class.java)
?: throw SilentException.UnsupportedBlockchain(chain) ?: throw SilentException.UnsupportedBlockchain(chain)
} }
private fun initAddress(request: BlockchainOuterClass.BalanceRequest): Flux<TrackedAddress> { private fun initAddress(request: BlockchainOuterClass.BalanceRequest): Flux<TrackedAddress> {
val chain = Chain.byId(request.asset.chainValue) val chain = Chain.byId(request.asset.chainValue)
if (!upstreams.isAvailable(chain)) { if (!multistreamHolder.isAvailable(chain)) {
return Flux.error(SilentException.UnsupportedBlockchain(request.asset.chainValue)) return Flux.error(SilentException.UnsupportedBlockchain(request.asset.chainValue))
} }
if (request.asset.code?.toLowerCase() != "ether") { if (request.asset.code?.toLowerCase() != "ether") {

View File

@@ -23,8 +23,8 @@ import io.emeraldpay.dshackle.BlockchainType
import io.emeraldpay.dshackle.SilentException import io.emeraldpay.dshackle.SilentException
import io.emeraldpay.dshackle.data.BlockContainer import io.emeraldpay.dshackle.data.BlockContainer
import io.emeraldpay.dshackle.data.TxId import io.emeraldpay.dshackle.data.TxId
import io.emeraldpay.dshackle.upstream.Upstreams import io.emeraldpay.dshackle.upstream.MultistreamHolder
import io.emeraldpay.dshackle.upstream.ethereum.EthereumChainUpstream import io.emeraldpay.dshackle.upstream.ethereum.EthereumMultistream
import io.emeraldpay.grpc.Chain import io.emeraldpay.grpc.Chain
import io.infinitape.etherjar.domain.BlockHash import io.infinitape.etherjar.domain.BlockHash
import io.infinitape.etherjar.domain.TransactionId import io.infinitape.etherjar.domain.TransactionId
@@ -48,7 +48,7 @@ import kotlin.math.min
@Service @Service
class TrackEthereumTx( class TrackEthereumTx(
@Autowired private val upstreams: Upstreams @Autowired private val multistreamHolder: MultistreamHolder
) : TrackTx { ) : TrackTx {
companion object { companion object {
@@ -63,7 +63,7 @@ class TrackEthereumTx(
private val log = LoggerFactory.getLogger(TrackEthereumTx::class.java) private val log = LoggerFactory.getLogger(TrackEthereumTx::class.java)
override fun isSupported(chain: Chain): Boolean { override fun isSupported(chain: Chain): Boolean {
return BlockchainType.fromBlockchain(chain) == BlockchainType.ETHEREUM && upstreams.isAvailable(chain) return BlockchainType.fromBlockchain(chain) == BlockchainType.ETHEREUM && multistreamHolder.isAvailable(chain)
} }
override fun subscribe(request: BlockchainOuterClass.TxStatusRequest): Flux<BlockchainOuterClass.TxStatus> { override fun subscribe(request: BlockchainOuterClass.TxStatusRequest): Flux<BlockchainOuterClass.TxStatus> {
@@ -83,12 +83,12 @@ class TrackEthereumTx(
} }
fun getUpstream(chain: Chain): EthereumChainUpstream { fun getUpstream(chain: Chain): EthereumMultistream {
return upstreams.getUpstream(chain)?.cast(EthereumChainUpstream::class.java) return multistreamHolder.getUpstream(chain)?.cast(EthereumMultistream::class.java)
?: throw SilentException.UnsupportedBlockchain(chain) ?: throw SilentException.UnsupportedBlockchain(chain)
} }
fun subscribe(base: TxDetails, up: EthereumChainUpstream): Flux<TxDetails> { fun subscribe(base: TxDetails, up: EthereumMultistream): Flux<TxDetails> {
var latestTx = base var latestTx = base
val untilFound = Mono.just(latestTx) val untilFound = Mono.just(latestTx)
@@ -213,7 +213,7 @@ class TrackEthereumTx(
} }
} }
fun updateFromBlock(upstream: EthereumChainUpstream, tx: TxDetails, blockTx: TransactionJson): Mono<TxDetails> { fun updateFromBlock(upstream: EthereumMultistream, tx: TxDetails, blockTx: TransactionJson): Mono<TxDetails> {
return if (blockTx.blockNumber != null && blockTx.blockHash != null && blockTx.blockHash != ZERO_BLOCK) { return if (blockTx.blockNumber != null && blockTx.blockHash != null && blockTx.blockHash != ZERO_BLOCK) {
val updated = tx.withStatus( val updated = tx.withStatus(
blockHash = blockTx.blockHash, blockHash = blockTx.blockHash,

View File

@@ -22,7 +22,7 @@ import io.emeraldpay.dshackle.FileResolver
import io.emeraldpay.dshackle.cache.CachesFactory import io.emeraldpay.dshackle.cache.CachesFactory
import io.emeraldpay.dshackle.config.UpstreamsConfig import io.emeraldpay.dshackle.config.UpstreamsConfig
import io.emeraldpay.dshackle.reader.Reader import io.emeraldpay.dshackle.reader.Reader
import io.emeraldpay.dshackle.upstream.CurrentUpstreams import io.emeraldpay.dshackle.upstream.CurrentMultistreamHolder
import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinUpstream import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinUpstream
import io.emeraldpay.dshackle.upstream.calls.CallMethods import io.emeraldpay.dshackle.upstream.calls.CallMethods
import io.emeraldpay.dshackle.upstream.calls.ManagedCallMethods import io.emeraldpay.dshackle.upstream.calls.ManagedCallMethods
@@ -45,7 +45,7 @@ import kotlin.collections.HashMap
@Repository @Repository
open class ConfiguredUpstreams( open class ConfiguredUpstreams(
@Autowired private val objectMapper: ObjectMapper, @Autowired private val objectMapper: ObjectMapper,
@Autowired private val currentUpstreams: CurrentUpstreams, @Autowired private val currentUpstreams: CurrentMultistreamHolder,
@Autowired private val fileResolver: FileResolver, @Autowired private val fileResolver: FileResolver,
@Autowired private val config: UpstreamsConfig, @Autowired private val config: UpstreamsConfig,
@Autowired private val cachesFactory: CachesFactory @Autowired private val cachesFactory: CachesFactory
@@ -201,8 +201,7 @@ open class ConfiguredUpstreams(
endpoint.port ?: 2449, endpoint.port ?: 2449,
objectMapper, objectMapper,
endpoint.auth, endpoint.auth,
fileResolver, fileResolver
cachesFactory
).apply { ).apply {
timeout = options.timeout timeout = options.timeout
} }
@@ -214,7 +213,6 @@ open class ConfiguredUpstreams(
.subscribe(currentUpstreams::update) .subscribe(currentUpstreams::update)
} }
private fun buildHttpClient(config: UpstreamsConfig.Upstream<out UpstreamsConfig.RpcConnection>): JsonRpcHttpClient? { private fun buildHttpClient(config: UpstreamsConfig.Upstream<out UpstreamsConfig.RpcConnection>): JsonRpcHttpClient? {
val conn = config.connection!! val conn = config.connection!!
val urls = ArrayList<URI>() val urls = ArrayList<URI>()

View File

@@ -1,136 +0,0 @@
/**
* Copyright (c) 2020 EmeraldPay, Inc
* Copyright (c) 2019 ETCDEV GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.emeraldpay.dshackle.upstream
import io.emeraldpay.dshackle.cache.Caches
import io.emeraldpay.dshackle.reader.Reader
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
import io.emeraldpay.grpc.Chain
import org.slf4j.LoggerFactory
import org.springframework.context.Lifecycle
import reactor.core.Disposable
import reactor.core.publisher.Mono
import java.lang.IllegalStateException
import java.time.Duration
/**
* General interface to upstream(s) to a single chain
*/
abstract class ChainUpstreams(
val chain: Chain,
private val upstreams: MutableList<Upstream>,
caches: Caches
) : AggregatedUpstream(caches), Lifecycle {
private val log = LoggerFactory.getLogger(ChainUpstreams::class.java)
private var seq = 0
protected var lagObserver: HeadLagObserver? = null
private var subscription: Disposable? = null
open fun init() {
onUpstreamsUpdated()
}
abstract fun updateHead(): Head
abstract fun setHead(head: Head)
override fun getId(): String {
return "!all:${chain.chainCode}"
}
override fun isRunning(): Boolean {
return subscription != null
}
override fun start() {
super.start()
subscription = observeStatus()
.distinctUntilChanged()
.subscribe { printStatus() }
}
override fun stop() {
super.stop()
subscription?.dispose()
subscription = null
getHead().let {
if (it is Lifecycle) {
it.stop()
}
}
lagObserver?.stop()
}
override fun getAll(): List<Upstream> {
return upstreams
}
override fun addUpstream(upstream: Upstream) {
upstreams.add(upstream)
setHead(updateHead())
onUpstreamsUpdated()
}
fun removeUpstream(id: String) {
if (upstreams.removeIf { it.getId() == id }) {
setHead(updateHead())
onUpstreamsUpdated()
}
}
override fun getApiSource(matcher: Selector.Matcher): ApiSource {
val i = seq++
if (seq >= Int.MAX_VALUE / 2) {
seq = 0
}
return FilteredApis(upstreams, matcher, i)
}
override fun getDirectApi(matcher: Selector.Matcher): Mono<Reader<JsonRpcRequest, JsonRpcResponse>> {
val apis = getApiSource(matcher)
apis.request(1)
return Mono.from(apis)
.switchIfEmpty(Mono.error(Exception("No API available")))
}
override fun setLag(lag: Long) {
}
override fun getLag(): Long {
return 0
}
fun printStatus() {
var height: Long? = null
try {
height = getHead().getFlux().next().block(Duration.ofSeconds(1))?.height
} catch (e: IllegalStateException) {
//timout
} catch (e: Exception) {
log.warn("Head processing error: ${e.javaClass} ${e.message}")
}
val statuses = upstreams.map { it.getStatus() }
.groupBy { it }
.map { "${it.key.name}/${it.value.size}" }
.joinToString(",")
val lag = upstreams.map { it.getLag() }
.joinToString(", ")
log.info("State of ${chain.chainCode}: height=${height ?: '?'}, status=$statuses, lag=[$lag]")
}
}

View File

@@ -21,12 +21,12 @@ import io.emeraldpay.dshackle.BlockchainType
import io.emeraldpay.dshackle.cache.CachesEnabled import io.emeraldpay.dshackle.cache.CachesEnabled
import io.emeraldpay.dshackle.cache.CachesFactory import io.emeraldpay.dshackle.cache.CachesFactory
import io.emeraldpay.dshackle.startup.UpstreamChange import io.emeraldpay.dshackle.startup.UpstreamChange
import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinChainUpstreams import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinMultistream
import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinUpstream import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinUpstream
import io.emeraldpay.dshackle.upstream.calls.DefaultBitcoinMethods import io.emeraldpay.dshackle.upstream.calls.DefaultBitcoinMethods
import io.emeraldpay.dshackle.upstream.calls.CallMethods import io.emeraldpay.dshackle.upstream.calls.CallMethods
import io.emeraldpay.dshackle.upstream.calls.DefaultEthereumMethods import io.emeraldpay.dshackle.upstream.calls.DefaultEthereumMethods
import io.emeraldpay.dshackle.upstream.ethereum.EthereumChainUpstream import io.emeraldpay.dshackle.upstream.ethereum.EthereumMultistream
import io.emeraldpay.dshackle.upstream.ethereum.EthereumUpstream import io.emeraldpay.dshackle.upstream.ethereum.EthereumUpstream
import io.emeraldpay.grpc.Chain import io.emeraldpay.grpc.Chain
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
@@ -42,14 +42,14 @@ import java.util.concurrent.locks.ReentrantLock
import kotlin.concurrent.withLock import kotlin.concurrent.withLock
@Repository @Repository
class CurrentUpstreams( class CurrentMultistreamHolder(
@Autowired private val objectMapper: ObjectMapper, @Autowired private val objectMapper: ObjectMapper,
@Autowired private val cachesFactory: CachesFactory @Autowired private val cachesFactory: CachesFactory
): Upstreams { ) : MultistreamHolder {
private val log = LoggerFactory.getLogger(CurrentUpstreams::class.java) private val log = LoggerFactory.getLogger(CurrentMultistreamHolder::class.java)
private val chainMapping = ConcurrentHashMap<Chain, ChainUpstreams>() private val chainMapping = ConcurrentHashMap<Chain, Multistream>()
private val chainsBus = TopicProcessor.create<Chain>() private val chainsBus = TopicProcessor.create<Chain>()
private val callTargets = HashMap<Chain, CallMethods>() private val callTargets = HashMap<Chain, CallMethods>()
private val updateLock = ReentrantLock() private val updateLock = ReentrantLock()
@@ -60,17 +60,17 @@ class CurrentUpstreams(
when (BlockchainType.fromBlockchain(chain)) { when (BlockchainType.fromBlockchain(chain)) {
BlockchainType.ETHEREUM -> { BlockchainType.ETHEREUM -> {
val up = change.upstream.cast(EthereumUpstream::class.java) val up = change.upstream.cast(EthereumUpstream::class.java)
val current = chainMapping[chain] as ChainUpstreams? val current = chainMapping[chain] as Multistream?
val factory = Callable { val factory = Callable {
EthereumChainUpstream(chain, ArrayList(), cachesFactory.getCaches(chain), objectMapper) as ChainUpstreams EthereumMultistream(chain, ArrayList(), cachesFactory.getCaches(chain), objectMapper) as Multistream
} }
processUpdate(change, up, current, factory) processUpdate(change, up, current, factory)
} }
BlockchainType.BITCOIN -> { BlockchainType.BITCOIN -> {
val up = change.upstream.cast(BitcoinUpstream::class.java) val up = change.upstream.cast(BitcoinUpstream::class.java)
val current = chainMapping[chain] as ChainUpstreams? val current = chainMapping[chain] as Multistream?
val factory = Callable { val factory = Callable {
BitcoinChainUpstreams(chain, ArrayList(), cachesFactory.getCaches(chain), objectMapper) as ChainUpstreams BitcoinMultistream(chain, ArrayList(), cachesFactory.getCaches(chain), objectMapper) as Multistream
} }
processUpdate(change, up, current, factory) processUpdate(change, up, current, factory)
} }
@@ -81,7 +81,7 @@ class CurrentUpstreams(
} }
} }
fun processUpdate(change: UpstreamChange, up: Upstream, current: ChainUpstreams?, factory: Callable<ChainUpstreams>) { fun processUpdate(change: UpstreamChange, up: Upstream, current: Multistream?, factory: Callable<Multistream>) {
val chain = change.chain val chain = change.chain
if (change.type == UpstreamChange.ChangeType.REMOVED) { if (change.type == UpstreamChange.ChangeType.REMOVED) {
current?.removeUpstream(up.getId()) current?.removeUpstream(up.getId())
@@ -109,7 +109,7 @@ class CurrentUpstreams(
} }
} }
override fun getUpstream(chain: Chain): AggregatedUpstream? { override fun getUpstream(chain: Chain): Multistream? {
return chainMapping[chain] return chainMapping[chain]
} }

View File

@@ -16,7 +16,6 @@
*/ */
package io.emeraldpay.dshackle.upstream package io.emeraldpay.dshackle.upstream
import com.fasterxml.jackson.databind.ObjectMapper
import io.emeraldpay.dshackle.cache.* import io.emeraldpay.dshackle.cache.*
import io.emeraldpay.dshackle.config.UpstreamsConfig import io.emeraldpay.dshackle.config.UpstreamsConfig
import io.emeraldpay.dshackle.reader.Reader import io.emeraldpay.dshackle.reader.Reader
@@ -24,6 +23,8 @@ import io.emeraldpay.dshackle.upstream.calls.AggregatedCallMethods
import io.emeraldpay.dshackle.upstream.calls.CallMethods import io.emeraldpay.dshackle.upstream.calls.CallMethods
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
import io.emeraldpay.grpc.Chain
import org.slf4j.LoggerFactory
import org.springframework.context.Lifecycle import org.springframework.context.Lifecycle
import reactor.core.Disposable import reactor.core.Disposable
import reactor.core.publisher.Flux import reactor.core.publisher.Flux
@@ -38,33 +39,70 @@ import kotlin.concurrent.withLock
/** /**
* Aggregation of multiple upstreams responding to a single blockchain * Aggregation of multiple upstreams responding to a single blockchain
*/ */
abstract class AggregatedUpstream( abstract class Multistream(
val chain: Chain,
private val upstreams: MutableList<Upstream>,
val caches: Caches val caches: Caches
) : Upstream, Lifecycle { ) : Upstream, Lifecycle {
companion object {
private val log = LoggerFactory.getLogger(Multistream::class.java)
}
private var cacheSubscription: Disposable? = null private var cacheSubscription: Disposable? = null
private val reconfigLock = ReentrantLock() private val reconfigLock = ReentrantLock()
private var callMethods: CallMethods? = null private var callMethods: CallMethods? = null
private var seq = 0
protected var lagObserver: HeadLagObserver? = null
private var subscription: Disposable? = null
open fun init() {
onUpstreamsUpdated()
}
/** /**
* Get list of all underlying upstreams * Get list of all underlying upstreams
*/ */
abstract fun getAll(): List<Upstream> fun getAll(): List<Upstream> {
return upstreams
}
/** /**
* Add an upstream * Add an upstream
*/ */
abstract fun addUpstream(upstream: Upstream) fun addUpstream(upstream: Upstream) {
upstreams.add(upstream)
setHead(updateHead())
onUpstreamsUpdated()
}
fun removeUpstream(id: String) {
if (upstreams.removeIf { it.getId() == id }) {
setHead(updateHead())
onUpstreamsUpdated()
}
}
/** /**
* Get a source for direct APIs * Get a source for direct APIs
*/ */
abstract fun getApiSource(matcher: Selector.Matcher): ApiSource fun getApiSource(matcher: Selector.Matcher): ApiSource {
val i = seq++
if (seq >= Int.MAX_VALUE / 2) {
seq = 0
}
return FilteredApis(upstreams, matcher, i)
}
/** /**
* Finds an API that executed directly on a remote. * Finds an API that executed directly on a remote.
*/ */
abstract fun getDirectApi(matcher: Selector.Matcher): Mono<Reader<JsonRpcRequest, JsonRpcResponse>> fun getDirectApi(matcher: Selector.Matcher): Mono<Reader<JsonRpcRequest, JsonRpcResponse>> {
val apis = getApiSource(matcher)
apis.request(1)
return Mono.from(apis)
.switchIfEmpty(Mono.error(Exception("No API available")))
}
/** /**
* Finds an API that leverages caches and other optimizations/transformations of the request. * Finds an API that leverages caches and other optimizations/transformations of the request.
@@ -109,11 +147,22 @@ abstract class AggregatedUpstream(
} }
override fun start() { override fun start() {
subscription = observeStatus()
.distinctUntilChanged()
.subscribe { printStatus() }
} }
override fun stop() { override fun stop() {
cacheSubscription?.dispose() cacheSubscription?.dispose()
cacheSubscription = null cacheSubscription = null
subscription?.dispose()
subscription = null
getHead().let {
if (it is Lifecycle) {
it.stop()
}
}
lagObserver?.stop()
} }
fun onHeadUpdated(head: Head) { fun onHeadUpdated(head: Head) {
@@ -125,6 +174,43 @@ abstract class AggregatedUpstream(
} }
} }
abstract fun updateHead(): Head
abstract fun setHead(head: Head)
override fun getId(): String {
return "!all:${chain.chainCode}"
}
override fun isRunning(): Boolean {
return subscription != null
}
override fun setLag(lag: Long) {
}
override fun getLag(): Long {
return 0
}
fun printStatus() {
var height: Long? = null
try {
height = getHead().getFlux().next().block(Duration.ofSeconds(1))?.height
} catch (e: java.lang.IllegalStateException) {
//timout
} catch (e: Exception) {
log.warn("Head processing error: ${e.javaClass} ${e.message}")
}
val statuses = upstreams.map { it.getStatus() }
.groupBy { it }
.map { "${it.key.name}/${it.value.size}" }
.joinToString(",")
val lag = upstreams.map { it.getLag() }
.joinToString(", ")
log.info("State of ${chain.chainCode}: height=${height ?: '?'}, status=$statuses, lag=[$lag]")
}
// -------------------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------------------
class UpstreamStatus(val upstream: Upstream, val status: UpstreamAvailability, val ts: Instant = Instant.now()) class UpstreamStatus(val upstream: Upstream, val status: UpstreamAvailability, val ts: Instant = Instant.now())

View File

@@ -16,16 +16,15 @@
*/ */
package io.emeraldpay.dshackle.upstream package io.emeraldpay.dshackle.upstream
import io.emeraldpay.dshackle.reader.Reader
import io.emeraldpay.dshackle.upstream.calls.CallMethods import io.emeraldpay.dshackle.upstream.calls.CallMethods
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
import io.emeraldpay.grpc.Chain import io.emeraldpay.grpc.Chain
import reactor.core.publisher.Flux import reactor.core.publisher.Flux
import reactor.core.publisher.Mono
interface Upstreams { /**
fun getUpstream(chain: Chain): AggregatedUpstream? * Holds Multistreams configured for a chain.
*/
interface MultistreamHolder {
fun getUpstream(chain: Chain): Multistream?
fun getAvailable(): List<Chain> fun getAvailable(): List<Chain>
fun observeChains(): Flux<Chain> fun observeChains(): Flux<Chain>
fun getDefaultMethods(chain: Chain): CallMethods fun getDefaultMethods(chain: Chain): CallMethods

View File

@@ -27,20 +27,18 @@ import org.slf4j.LoggerFactory
import org.springframework.context.Lifecycle import org.springframework.context.Lifecycle
import reactor.core.publisher.Mono import reactor.core.publisher.Mono
open class BitcoinChainUpstreams( open class BitcoinMultistream(
chain: Chain, chain: Chain,
val upstreams: MutableList<BitcoinUpstream>, val upstreams: MutableList<BitcoinUpstream>,
caches: Caches, caches: Caches,
private val objectMapper: ObjectMapper private val objectMapper: ObjectMapper
) : ChainUpstreams(chain, upstreams as MutableList<Upstream>, caches), Lifecycle { ) : Multistream(chain, upstreams as MutableList<Upstream>, caches), Lifecycle {
companion object { companion object {
private val log = LoggerFactory.getLogger(BitcoinChainUpstreams::class.java) private val log = LoggerFactory.getLogger(BitcoinMultistream::class.java)
} }
private var head: Head? = null private var head: Head? = null
//TODO head
private var reader = BitcoinReader(this, EmptyHead(), objectMapper) private var reader = BitcoinReader(this, EmptyHead(), objectMapper)
override fun init() { override fun init() {

View File

@@ -26,7 +26,7 @@ import reactor.core.publisher.Mono
import reactor.kotlin.core.publisher.cast import reactor.kotlin.core.publisher.cast
open class BitcoinReader( open class BitcoinReader(
private val upstreams: BitcoinChainUpstreams, private val upstreams: BitcoinMultistream,
head: Head, head: Head,
private val objectMapper: ObjectMapper private val objectMapper: ObjectMapper
) : Lifecycle { ) : Lifecycle {

View File

@@ -30,7 +30,7 @@ import java.util.concurrent.atomic.AtomicReference
import java.util.concurrent.locks.ReentrantLock import java.util.concurrent.locks.ReentrantLock
open class CachingMempoolData( open class CachingMempoolData(
private val upstreams: BitcoinChainUpstreams, private val upstreams: BitcoinMultistream,
private val head: Head, private val head: Head,
private val objectMapper: ObjectMapper private val objectMapper: ObjectMapper
) : Lifecycle { ) : Lifecycle {

View File

@@ -28,15 +28,15 @@ import org.slf4j.LoggerFactory
import org.springframework.context.Lifecycle import org.springframework.context.Lifecycle
import reactor.core.publisher.Mono import reactor.core.publisher.Mono
open class EthereumChainUpstream( open class EthereumMultistream(
chain: Chain, chain: Chain,
val upstreams: MutableList<EthereumUpstream>, val upstreams: MutableList<EthereumUpstream>,
caches: Caches, caches: Caches,
private val objectMapper: ObjectMapper private val objectMapper: ObjectMapper
) : ChainUpstreams(chain, upstreams as MutableList<Upstream>, caches) { ) : Multistream(chain, upstreams as MutableList<Upstream>, caches) {
companion object { companion object {
private val log = LoggerFactory.getLogger(EthereumChainUpstream::class.java) private val log = LoggerFactory.getLogger(EthereumMultistream::class.java)
} }
private var head: Head? = null private var head: Head? = null

View File

@@ -21,10 +21,8 @@ import io.emeraldpay.dshackle.cache.Caches
import io.emeraldpay.dshackle.cache.CurrentBlockCache import io.emeraldpay.dshackle.cache.CurrentBlockCache
import io.emeraldpay.dshackle.data.* import io.emeraldpay.dshackle.data.*
import io.emeraldpay.dshackle.reader.* import io.emeraldpay.dshackle.reader.*
import io.emeraldpay.dshackle.upstream.AggregatedUpstream import io.emeraldpay.dshackle.upstream.Multistream
import io.emeraldpay.dshackle.upstream.Selector import io.emeraldpay.dshackle.upstream.Selector
import io.emeraldpay.dshackle.upstream.Upstream
import io.emeraldpay.dshackle.upstream.Upstreams
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
import io.infinitape.etherjar.domain.Address import io.infinitape.etherjar.domain.Address
@@ -35,7 +33,6 @@ import io.infinitape.etherjar.hex.HexQuantity
import io.infinitape.etherjar.rpc.RpcException import io.infinitape.etherjar.rpc.RpcException
import io.infinitape.etherjar.rpc.RpcResponseError import io.infinitape.etherjar.rpc.RpcResponseError
import io.infinitape.etherjar.rpc.json.BlockJson import io.infinitape.etherjar.rpc.json.BlockJson
import io.infinitape.etherjar.rpc.json.BlockTag
import io.infinitape.etherjar.rpc.json.TransactionJson import io.infinitape.etherjar.rpc.json.TransactionJson
import io.infinitape.etherjar.rpc.json.TransactionRefJson import io.infinitape.etherjar.rpc.json.TransactionRefJson
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
@@ -48,7 +45,7 @@ import java.util.concurrent.TimeoutException
import java.util.function.Function import java.util.function.Function
open class EthereumReader( open class EthereumReader(
private val up: AggregatedUpstream, private val up: Multistream,
private val caches: Caches, private val caches: Caches,
private val objectMapper: ObjectMapper private val objectMapper: ObjectMapper
) : Lifecycle { ) : Lifecycle {

View File

@@ -22,8 +22,6 @@ 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.Defaults import io.emeraldpay.dshackle.Defaults
import io.emeraldpay.dshackle.cache.Caches
import io.emeraldpay.dshackle.cache.CachesEnabled
import io.emeraldpay.dshackle.config.UpstreamsConfig import io.emeraldpay.dshackle.config.UpstreamsConfig
import io.emeraldpay.dshackle.data.BlockContainer import io.emeraldpay.dshackle.data.BlockContainer
import io.emeraldpay.dshackle.data.BlockId import io.emeraldpay.dshackle.data.BlockId
@@ -39,7 +37,6 @@ import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
import io.emeraldpay.grpc.Chain import io.emeraldpay.grpc.Chain
import io.infinitape.etherjar.domain.BlockHash import io.infinitape.etherjar.domain.BlockHash
import io.infinitape.etherjar.rpc.* import io.infinitape.etherjar.rpc.*
import io.infinitape.etherjar.rpc.emerald.ReactorEmeraldClient
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.context.Lifecycle import org.springframework.context.Lifecycle
import reactor.core.Disposable import reactor.core.Disposable

View File

@@ -22,7 +22,6 @@ import io.emeraldpay.api.proto.ReactorBlockchainGrpc
import io.emeraldpay.dshackle.BlockchainType import io.emeraldpay.dshackle.BlockchainType
import io.emeraldpay.dshackle.Defaults import io.emeraldpay.dshackle.Defaults
import io.emeraldpay.dshackle.FileResolver import io.emeraldpay.dshackle.FileResolver
import io.emeraldpay.dshackle.cache.CachesFactory
import io.emeraldpay.dshackle.config.AuthConfig import io.emeraldpay.dshackle.config.AuthConfig
import io.emeraldpay.dshackle.upstream.UpstreamAvailability import io.emeraldpay.dshackle.upstream.UpstreamAvailability
import io.emeraldpay.dshackle.startup.UpstreamChange import io.emeraldpay.dshackle.startup.UpstreamChange
@@ -30,7 +29,6 @@ import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcGrpcClient
import io.emeraldpay.grpc.Chain import io.emeraldpay.grpc.Chain
import io.grpc.ManagedChannelBuilder import io.grpc.ManagedChannelBuilder
import io.grpc.netty.NettyChannelBuilder import io.grpc.netty.NettyChannelBuilder
import io.infinitape.etherjar.rpc.emerald.ReactorEmeraldClient
import io.netty.handler.ssl.* import io.netty.handler.ssl.*
import org.apache.commons.lang3.StringUtils import org.apache.commons.lang3.StringUtils
import org.apache.commons.lang3.exception.ExceptionUtils import org.apache.commons.lang3.exception.ExceptionUtils
@@ -50,8 +48,7 @@ class GrpcUpstreams(
private val port: Int, private val port: Int,
private val objectMapper: ObjectMapper, private val objectMapper: ObjectMapper,
private val auth: AuthConfig.ClientTlsAuth? = null, private val auth: AuthConfig.ClientTlsAuth? = null,
private val fileResolver: FileResolver, private val fileResolver: FileResolver
private val cachesFactory: CachesFactory
) { ) {
private val log = LoggerFactory.getLogger(GrpcUpstreams::class.java) private val log = LoggerFactory.getLogger(GrpcUpstreams::class.java)

View File

@@ -23,8 +23,7 @@ import io.emeraldpay.dshackle.test.TestingCommons
import io.emeraldpay.dshackle.quorum.AlwaysQuorum import io.emeraldpay.dshackle.quorum.AlwaysQuorum
import io.emeraldpay.dshackle.quorum.NonEmptyQuorum import io.emeraldpay.dshackle.quorum.NonEmptyQuorum
import io.emeraldpay.dshackle.upstream.Selector import io.emeraldpay.dshackle.upstream.Selector
import io.emeraldpay.dshackle.upstream.Upstream import io.emeraldpay.dshackle.upstream.MultistreamHolder
import io.emeraldpay.dshackle.upstream.Upstreams
import io.emeraldpay.grpc.Chain import io.emeraldpay.grpc.Chain
import io.infinitape.etherjar.rpc.ReactorRpcClient import io.infinitape.etherjar.rpc.ReactorRpcClient
import io.infinitape.etherjar.rpc.RpcException import io.infinitape.etherjar.rpc.RpcException
@@ -44,7 +43,7 @@ class NativeCallSpec extends Specification {
def "Quorum is applied"() { def "Quorum is applied"() {
setup: setup:
def quorum = Spy(new AlwaysQuorum()) def quorum = Spy(new AlwaysQuorum())
def upstreams = Stub(Upstreams) def upstreams = Stub(MultistreamHolder)
def apiMock = TestingCommons.api() def apiMock = TestingCommons.api()
apiMock.answer("eth_test", [], "foo") apiMock.answer("eth_test", [], "foo")
@@ -67,7 +66,7 @@ class NativeCallSpec extends Specification {
setup: setup:
def quorum = Spy(new NonEmptyQuorum(TestingCommons.objectMapper(), 3)) def quorum = Spy(new NonEmptyQuorum(TestingCommons.objectMapper(), 3))
def upstreams = Stub(Upstreams) def upstreams = Stub(MultistreamHolder)
def apiMock = TestingCommons.api() def apiMock = TestingCommons.api()
apiMock.answerOnce("eth_test", [], null) apiMock.answerOnce("eth_test", [], null)
@@ -93,7 +92,7 @@ class NativeCallSpec extends Specification {
setup: setup:
def quorum = Spy(new NonEmptyQuorum(TestingCommons.objectMapper(), 3)) def quorum = Spy(new NonEmptyQuorum(TestingCommons.objectMapper(), 3))
def upstreams = Stub(Upstreams) def upstreams = Stub(MultistreamHolder)
def apiMock = TestingCommons.api() def apiMock = TestingCommons.api()
apiMock.answerOnce("eth_test", [], null) apiMock.answerOnce("eth_test", [], null)
@@ -119,7 +118,7 @@ class NativeCallSpec extends Specification {
setup: setup:
def quorum = Spy(new NonEmptyQuorum(TestingCommons.objectMapper(), 3)) def quorum = Spy(new NonEmptyQuorum(TestingCommons.objectMapper(), 3))
def upstreams = Stub(Upstreams) def upstreams = Stub(MultistreamHolder)
ReactorRpcClient rpcClient = Stub(ReactorRpcClient) ReactorRpcClient rpcClient = Stub(ReactorRpcClient)
def apiMock = TestingCommons.api() def apiMock = TestingCommons.api()
@@ -143,7 +142,7 @@ class NativeCallSpec extends Specification {
setup: setup:
def quorum = Spy(new NonEmptyQuorum(TestingCommons.objectMapper(), 3)) def quorum = Spy(new NonEmptyQuorum(TestingCommons.objectMapper(), 3))
def upstreams = Stub(Upstreams) def upstreams = Stub(MultistreamHolder)
ReactorRpcClient rpcClient = Stub(ReactorRpcClient) ReactorRpcClient rpcClient = Stub(ReactorRpcClient)
def apiMock = TestingCommons.api() def apiMock = TestingCommons.api()
@@ -167,7 +166,7 @@ class NativeCallSpec extends Specification {
def "Packs call exception into response with id"() { def "Packs call exception into response with id"() {
setup: setup:
def upstreams = Stub(Upstreams) def upstreams = Stub(MultistreamHolder)
def nativeCall = new NativeCall(upstreams, TestingCommons.objectMapper()) def nativeCall = new NativeCall(upstreams, TestingCommons.objectMapper())
when: when:
def resp = nativeCall.processException(new NativeCall.CallFailure(5, new IllegalArgumentException("test test"))) def resp = nativeCall.processException(new NativeCall.CallFailure(5, new IllegalArgumentException("test test")))
@@ -184,7 +183,7 @@ class NativeCallSpec extends Specification {
def "Packs unknown exception into response"() { def "Packs unknown exception into response"() {
setup: setup:
def upstreams = Stub(Upstreams) def upstreams = Stub(MultistreamHolder)
def nativeCall = new NativeCall(upstreams, TestingCommons.objectMapper()) def nativeCall = new NativeCall(upstreams, TestingCommons.objectMapper())
when: when:
def resp = nativeCall.processException(new IllegalArgumentException("test test")) def resp = nativeCall.processException(new IllegalArgumentException("test test"))
@@ -200,7 +199,7 @@ class NativeCallSpec extends Specification {
def "Builds normal response"() { def "Builds normal response"() {
setup: setup:
def upstreams = Stub(Upstreams) def upstreams = Stub(MultistreamHolder)
def nativeCall = new NativeCall(upstreams, TestingCommons.objectMapper()) def nativeCall = new NativeCall(upstreams, TestingCommons.objectMapper())
def json = [jsonrpc:"2.0", id:1, result: "foo"] def json = [jsonrpc:"2.0", id:1, result: "foo"]
@@ -216,7 +215,7 @@ class NativeCallSpec extends Specification {
def "Returns error for invalid chain"() { def "Returns error for invalid chain"() {
setup: setup:
def upstreams = Stub(Upstreams) def upstreams = Stub(MultistreamHolder)
def nativeCall = new NativeCall(upstreams, TestingCommons.objectMapper()) def nativeCall = new NativeCall(upstreams, TestingCommons.objectMapper())
def req = BlockchainOuterClass.NativeCallRequest.newBuilder() def req = BlockchainOuterClass.NativeCallRequest.newBuilder()
@@ -239,7 +238,7 @@ class NativeCallSpec extends Specification {
def "Returns error for unsupported chain"() { def "Returns error for unsupported chain"() {
setup: setup:
def upstreams = Mock(Upstreams) def upstreams = Mock(MultistreamHolder)
def nativeCall = new NativeCall(upstreams, TestingCommons.objectMapper()) def nativeCall = new NativeCall(upstreams, TestingCommons.objectMapper())
def req = BlockchainOuterClass.NativeCallRequest.newBuilder() def req = BlockchainOuterClass.NativeCallRequest.newBuilder()
@@ -265,7 +264,7 @@ class NativeCallSpec extends Specification {
//TODO //TODO
def "Calls cache before remote"() { def "Calls cache before remote"() {
setup: setup:
def upstreams = Stub(Upstreams) def upstreams = Stub(MultistreamHolder)
def nativeCall = new NativeCall(upstreams, TestingCommons.objectMapper()) def nativeCall = new NativeCall(upstreams, TestingCommons.objectMapper())
def api = TestingCommons.api() def api = TestingCommons.api()
def upstream = TestingCommons.aggregatedUpstream(api) def upstream = TestingCommons.aggregatedUpstream(api)
@@ -284,7 +283,7 @@ class NativeCallSpec extends Specification {
//TODO //TODO
def "Uses cached value"() { def "Uses cached value"() {
setup: setup:
def upstreams = Stub(Upstreams) def upstreams = Stub(MultistreamHolder)
def nativeCall = new NativeCall(upstreams, TestingCommons.objectMapper()) def nativeCall = new NativeCall(upstreams, TestingCommons.objectMapper())
def upstream = TestingCommons.aggregatedUpstream(TestingCommons.api()) def upstream = TestingCommons.aggregatedUpstream(TestingCommons.api())
@@ -303,7 +302,7 @@ class NativeCallSpec extends Specification {
setup: setup:
def quorum = Spy(new AlwaysQuorum()) def quorum = Spy(new AlwaysQuorum())
def upstreams = Stub(Upstreams) def upstreams = Stub(MultistreamHolder)
def apiMock = TestingCommons.api() def apiMock = TestingCommons.api()
apiMock.answer("eth_test", [], null, 1, new TimeoutException("test 1")) apiMock.answer("eth_test", [], null, 1, new TimeoutException("test 1"))
@@ -329,7 +328,7 @@ class NativeCallSpec extends Specification {
setup: setup:
def quorum = Spy(new BroadcastQuorum(TestingCommons.objectMapper(), 3)) def quorum = Spy(new BroadcastQuorum(TestingCommons.objectMapper(), 3))
def upstreams = Stub(Upstreams) def upstreams = Stub(MultistreamHolder)
def apiMock = TestingCommons.api() def apiMock = TestingCommons.api()
apiMock.answer("eth_sendRawTransaction", ["0x1234"], apiMock.answer("eth_sendRawTransaction", ["0x1234"],

View File

@@ -23,7 +23,7 @@ import io.emeraldpay.api.proto.Common
import io.emeraldpay.dshackle.data.BlockContainer import io.emeraldpay.dshackle.data.BlockContainer
import io.emeraldpay.dshackle.test.EthereumUpstreamMock import io.emeraldpay.dshackle.test.EthereumUpstreamMock
import io.emeraldpay.dshackle.test.TestingCommons import io.emeraldpay.dshackle.test.TestingCommons
import io.emeraldpay.dshackle.test.UpstreamsMock import io.emeraldpay.dshackle.test.MultistreamHolderMock
import io.emeraldpay.dshackle.upstream.ethereum.EthereumUpstream import io.emeraldpay.dshackle.upstream.ethereum.EthereumUpstream
import io.emeraldpay.grpc.Chain import io.emeraldpay.grpc.Chain
import io.infinitape.etherjar.domain.BlockHash import io.infinitape.etherjar.domain.BlockHash
@@ -42,7 +42,7 @@ class StreamHeadSpec extends Specification {
def "Errors on unavailable chain"() { def "Errors on unavailable chain"() {
setup: setup:
def upstreams = new UpstreamsMock(Chain.ETHEREUM, Stub(EthereumUpstream)) def upstreams = new MultistreamHolderMock(Chain.ETHEREUM, Stub(EthereumUpstream))
def streamHead = new StreamHead(upstreams) def streamHead = new StreamHead(upstreams)
when: when:
def flux = streamHead.add( def flux = streamHead.add(
@@ -78,7 +78,7 @@ class StreamHeadSpec extends Specification {
} }
def upstream = new EthereumUpstreamMock(Chain.ETHEREUM, TestingCommons.api()) def upstream = new EthereumUpstreamMock(Chain.ETHEREUM, TestingCommons.api())
def upstreams = new UpstreamsMock(Chain.ETHEREUM, upstream) def upstreams = new MultistreamHolderMock(Chain.ETHEREUM, upstream)
def streamHead = new StreamHead(upstreams) def streamHead = new StreamHead(upstreams)
when: when:
def flux = streamHead.add( def flux = streamHead.add(

View File

@@ -19,18 +19,12 @@ import io.emeraldpay.api.proto.BlockchainOuterClass
import io.emeraldpay.api.proto.Common import io.emeraldpay.api.proto.Common
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.reader.Reader
import io.emeraldpay.dshackle.test.ReaderMock
import io.emeraldpay.dshackle.test.TestingCommons import io.emeraldpay.dshackle.test.TestingCommons
import io.emeraldpay.dshackle.test.UpstreamsMock import io.emeraldpay.dshackle.test.MultistreamHolderMock
import io.emeraldpay.dshackle.upstream.AggregatedUpstream
import io.emeraldpay.dshackle.upstream.Head import io.emeraldpay.dshackle.upstream.Head
import io.emeraldpay.dshackle.upstream.Upstream import io.emeraldpay.dshackle.upstream.MultistreamHolder
import io.emeraldpay.dshackle.upstream.Upstreams import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinMultistream
import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinChainUpstreams
import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinReader import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinReader
import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinUpstream
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
import io.emeraldpay.grpc.Chain import io.emeraldpay.grpc.Chain
import reactor.core.publisher.Flux import reactor.core.publisher.Flux
import reactor.core.publisher.Mono import reactor.core.publisher.Mono
@@ -49,7 +43,7 @@ class TrackBitcoinAddressSpec extends Specification {
setup: setup:
def json = this.class.getClassLoader().getResourceAsStream("bitcoin/unspent-one-addr.json") def json = this.class.getClassLoader().getResourceAsStream("bitcoin/unspent-one-addr.json")
def unspents = TestingCommons.objectMapper().readValue(json, List) def unspents = TestingCommons.objectMapper().readValue(json, List)
TrackBitcoinAddress track = new TrackBitcoinAddress(Stub(Upstreams)) TrackBitcoinAddress track = new TrackBitcoinAddress(Stub(MultistreamHolder))
when: when:
def total = track.getTotal(Chain.BITCOIN, ["1K7xkspJg7DDKNwzXgoRSDCUxiFsRegsSK"], unspents) def total = track.getTotal(Chain.BITCOIN, ["1K7xkspJg7DDKNwzXgoRSDCUxiFsRegsSK"], unspents)
@@ -64,7 +58,7 @@ class TrackBitcoinAddressSpec extends Specification {
setup: setup:
def json = this.class.getClassLoader().getResourceAsStream("bitcoin/unspent-two-addr.json") def json = this.class.getClassLoader().getResourceAsStream("bitcoin/unspent-two-addr.json")
def unspents = TestingCommons.objectMapper().readValue(json, List) def unspents = TestingCommons.objectMapper().readValue(json, List)
TrackBitcoinAddress track = new TrackBitcoinAddress(Stub(Upstreams)) TrackBitcoinAddress track = new TrackBitcoinAddress(Stub(MultistreamHolder))
when: when:
def total = track.getTotal(Chain.BITCOIN, ["1K7xkspJg7DDKNwzXgoRSDCUxiFsRegsSK"], unspents) def total = track.getTotal(Chain.BITCOIN, ["1K7xkspJg7DDKNwzXgoRSDCUxiFsRegsSK"], unspents)
@@ -79,7 +73,7 @@ class TrackBitcoinAddressSpec extends Specification {
setup: setup:
def json = this.class.getClassLoader().getResourceAsStream("bitcoin/unspent-two-addr.json") def json = this.class.getClassLoader().getResourceAsStream("bitcoin/unspent-two-addr.json")
def unspents = TestingCommons.objectMapper().readValue(json, List) def unspents = TestingCommons.objectMapper().readValue(json, List)
TrackBitcoinAddress track = new TrackBitcoinAddress(Stub(Upstreams)) TrackBitcoinAddress track = new TrackBitcoinAddress(Stub(MultistreamHolder))
when: when:
def total = track.getTotal(Chain.BITCOIN, ["1K7xkspJg7DDKNwzXgoRSDCUxiFsRegsSK", "35hK24tcLEWcgNA4JxpvbkNkoAcDGqQPsP"], unspents).sort { it.address.address } def total = track.getTotal(Chain.BITCOIN, ["1K7xkspJg7DDKNwzXgoRSDCUxiFsRegsSK", "35hK24tcLEWcgNA4JxpvbkNkoAcDGqQPsP"], unspents).sort { it.address.address }
@@ -99,7 +93,7 @@ class TrackBitcoinAddressSpec extends Specification {
def "Zero for empty unspents"() { def "Zero for empty unspents"() {
setup: setup:
TrackBitcoinAddress track = new TrackBitcoinAddress(Stub(Upstreams)) TrackBitcoinAddress track = new TrackBitcoinAddress(Stub(MultistreamHolder))
when: when:
def total = track.getTotal(Chain.BITCOIN, ["1K7xkspJg7DDKNwzXgoRSDCUxiFsRegsSK"], []) def total = track.getTotal(Chain.BITCOIN, ["1K7xkspJg7DDKNwzXgoRSDCUxiFsRegsSK"], [])
@@ -114,7 +108,7 @@ class TrackBitcoinAddressSpec extends Specification {
setup: setup:
def json = this.class.getClassLoader().getResourceAsStream("bitcoin/unspent-two-addr.json") def json = this.class.getClassLoader().getResourceAsStream("bitcoin/unspent-two-addr.json")
def unspents = TestingCommons.objectMapper().readValue(json, List) def unspents = TestingCommons.objectMapper().readValue(json, List)
TrackBitcoinAddress track = new TrackBitcoinAddress(Stub(Upstreams)) TrackBitcoinAddress track = new TrackBitcoinAddress(Stub(MultistreamHolder))
when: when:
def total = track.getTotal(Chain.BITCOIN, ["16rCmCmbuWDhPjWTrpQGaU3EPdZF7MTdUk", "1K7xkspJg7DDKNwzXgoRSDCUxiFsRegsSK"], unspents).sort { it.address.address } def total = track.getTotal(Chain.BITCOIN, ["16rCmCmbuWDhPjWTrpQGaU3EPdZF7MTdUk", "1K7xkspJg7DDKNwzXgoRSDCUxiFsRegsSK"], unspents).sort { it.address.address }
@@ -132,7 +126,7 @@ class TrackBitcoinAddressSpec extends Specification {
def "One address for single provided"() { def "One address for single provided"() {
setup: setup:
TrackBitcoinAddress track = new TrackBitcoinAddress(Stub(Upstreams)) TrackBitcoinAddress track = new TrackBitcoinAddress(Stub(MultistreamHolder))
def req = BlockchainOuterClass.BalanceRequest.newBuilder() def req = BlockchainOuterClass.BalanceRequest.newBuilder()
.setAddress( .setAddress(
Common.AnyAddress.newBuilder() Common.AnyAddress.newBuilder()
@@ -150,7 +144,7 @@ class TrackBitcoinAddressSpec extends Specification {
def "Sorted addresses for multiple provided"() { def "Sorted addresses for multiple provided"() {
setup: setup:
TrackBitcoinAddress track = new TrackBitcoinAddress(Stub(Upstreams)) TrackBitcoinAddress track = new TrackBitcoinAddress(Stub(MultistreamHolder))
def req = BlockchainOuterClass.BalanceRequest.newBuilder() def req = BlockchainOuterClass.BalanceRequest.newBuilder()
.setAddress( .setAddress(
Common.AnyAddress.newBuilder() Common.AnyAddress.newBuilder()
@@ -171,7 +165,7 @@ class TrackBitcoinAddressSpec extends Specification {
def "Null for no address provided"() { def "Null for no address provided"() {
setup: setup:
TrackBitcoinAddress track = new TrackBitcoinAddress(Stub(Upstreams)) TrackBitcoinAddress track = new TrackBitcoinAddress(Stub(MultistreamHolder))
def req = BlockchainOuterClass.BalanceRequest.newBuilder() def req = BlockchainOuterClass.BalanceRequest.newBuilder()
.build() .build()
when: when:
@@ -182,7 +176,7 @@ class TrackBitcoinAddressSpec extends Specification {
def "Build proto for common balance"() { def "Build proto for common balance"() {
setup: setup:
TrackBitcoinAddress track = new TrackBitcoinAddress(Stub(Upstreams)) TrackBitcoinAddress track = new TrackBitcoinAddress(Stub(MultistreamHolder))
def balance = new TrackBitcoinAddress.AddressBalance(Chain.BITCOIN, "1K7xkspJg7DDKNwzXgoRSDCUxiFsRegsSK", BigInteger.valueOf(123456)) def balance = new TrackBitcoinAddress.AddressBalance(Chain.BITCOIN, "1K7xkspJg7DDKNwzXgoRSDCUxiFsRegsSK", BigInteger.valueOf(123456))
when: when:
def act = track.buildResponse(balance) def act = track.buildResponse(balance)
@@ -195,7 +189,7 @@ class TrackBitcoinAddressSpec extends Specification {
def "Build proto for zero balance"() { def "Build proto for zero balance"() {
setup: setup:
TrackBitcoinAddress track = new TrackBitcoinAddress(Stub(Upstreams)) TrackBitcoinAddress track = new TrackBitcoinAddress(Stub(MultistreamHolder))
def balance = new TrackBitcoinAddress.AddressBalance(Chain.BITCOIN, "1K7xkspJg7DDKNwzXgoRSDCUxiFsRegsSK", BigInteger.ZERO) def balance = new TrackBitcoinAddress.AddressBalance(Chain.BITCOIN, "1K7xkspJg7DDKNwzXgoRSDCUxiFsRegsSK", BigInteger.ZERO)
when: when:
def act = track.buildResponse(balance) def act = track.buildResponse(balance)
@@ -208,7 +202,7 @@ class TrackBitcoinAddressSpec extends Specification {
def "Build proto for all bitcoins"() { def "Build proto for all bitcoins"() {
setup: setup:
TrackBitcoinAddress track = new TrackBitcoinAddress(Stub(Upstreams)) TrackBitcoinAddress track = new TrackBitcoinAddress(Stub(MultistreamHolder))
def balance = new TrackBitcoinAddress.AddressBalance(Chain.BITCOIN, "1K7xkspJg7DDKNwzXgoRSDCUxiFsRegsSK", BigInteger.valueOf(21_000_000).multiply(BigInteger.TEN.pow(8))) def balance = new TrackBitcoinAddress.AddressBalance(Chain.BITCOIN, "1K7xkspJg7DDKNwzXgoRSDCUxiFsRegsSK", BigInteger.valueOf(21_000_000).multiply(BigInteger.TEN.pow(8)))
when: when:
def act = track.buildResponse(balance) def act = track.buildResponse(balance)
@@ -227,7 +221,7 @@ class TrackBitcoinAddressSpec extends Specification {
1 * getFlux() >> Flux.from(blocks) 1 * getFlux() >> Flux.from(blocks)
} }
def upstream = null def upstream = null
upstream = Mock(BitcoinChainUpstreams) { upstream = Mock(BitcoinMultistream) {
_ * getReader() >> Mock(BitcoinReader) { _ * getReader() >> Mock(BitcoinReader) {
2 * listUnspent() >>> [ 2 * listUnspent() >>> [
Mono.just([]), Mono.just([]),
@@ -239,7 +233,7 @@ class TrackBitcoinAddressSpec extends Specification {
upstream upstream
} }
} }
Upstreams upstreams = new UpstreamsMock(Chain.BITCOIN, upstream) MultistreamHolder upstreams = new MultistreamHolderMock(Chain.BITCOIN, upstream)
TrackBitcoinAddress track = new TrackBitcoinAddress(upstreams) TrackBitcoinAddress track = new TrackBitcoinAddress(upstreams)
when: when:

View File

@@ -17,13 +17,10 @@ package io.emeraldpay.dshackle.rpc
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.reader.Reader
import io.emeraldpay.dshackle.upstream.Head import io.emeraldpay.dshackle.upstream.Head
import io.emeraldpay.dshackle.upstream.Upstream import io.emeraldpay.dshackle.upstream.MultistreamHolder
import io.emeraldpay.dshackle.upstream.Upstreams import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinMultistream
import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinChainUpstreams
import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinReader import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinReader
import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinUpstream
import io.emeraldpay.dshackle.upstream.bitcoin.CachingMempoolData import io.emeraldpay.dshackle.upstream.bitcoin.CachingMempoolData
import io.emeraldpay.grpc.Chain import io.emeraldpay.grpc.Chain
import reactor.core.publisher.Flux import reactor.core.publisher.Flux
@@ -38,7 +35,7 @@ class TrackBitcoinTxSpec extends Specification {
def "loadMempool() returns not found when not found"() { def "loadMempool() returns not found when not found"() {
setup: setup:
TrackBitcoinTx track = new TrackBitcoinTx(Stub(Upstreams)) TrackBitcoinTx track = new TrackBitcoinTx(Stub(MultistreamHolder))
CachingMempoolData mempoolAccess = Mock(CachingMempoolData) { CachingMempoolData mempoolAccess = Mock(CachingMempoolData) {
1 * get() >> Mono.just([ 1 * get() >> Mono.just([
@@ -46,7 +43,7 @@ class TrackBitcoinTxSpec extends Specification {
"d296c6d47335a7f283574b06f1d6303b30ac75631e081ab128346a549ad93350" "d296c6d47335a7f283574b06f1d6303b30ac75631e081ab128346a549ad93350"
]) ])
} }
BitcoinChainUpstreams upstream = Mock(BitcoinChainUpstreams) { BitcoinMultistream upstream = Mock(BitcoinMultistream) {
_ * getReader() >> Mock(BitcoinReader) { _ * getReader() >> Mock(BitcoinReader) {
_ * getMempool() >> mempoolAccess _ * getMempool() >> mempoolAccess
} }
@@ -65,14 +62,14 @@ class TrackBitcoinTxSpec extends Specification {
def "loadMempool() returns ok when found"() { def "loadMempool() returns ok when found"() {
setup: setup:
TrackBitcoinTx track = new TrackBitcoinTx(Stub(Upstreams)) TrackBitcoinTx track = new TrackBitcoinTx(Stub(MultistreamHolder))
CachingMempoolData mempoolAccess = Mock(CachingMempoolData) { CachingMempoolData mempoolAccess = Mock(CachingMempoolData) {
1 * get() >> Mono.just([ 1 * get() >> Mono.just([
"69cd44d7c641db82e69824523c7ac0c5c1e5628f025474529cf5ffe64527efc9", "69cd44d7c641db82e69824523c7ac0c5c1e5628f025474529cf5ffe64527efc9",
"d296c6d47335a7f283574b06f1d6303b30ac75631e081ab128346a549ad93350" "d296c6d47335a7f283574b06f1d6303b30ac75631e081ab128346a549ad93350"
]) ])
} }
BitcoinChainUpstreams upstream = Mock(BitcoinChainUpstreams) { BitcoinMultistream upstream = Mock(BitcoinMultistream) {
_ * getReader() >> Mock(BitcoinReader) { _ * getReader() >> Mock(BitcoinReader) {
_ * getMempool() >> mempoolAccess _ * getMempool() >> mempoolAccess
} }
@@ -91,9 +88,9 @@ class TrackBitcoinTxSpec extends Specification {
def "loadExiting() returns not found if not mined"() { def "loadExiting() returns not found if not mined"() {
setup: setup:
TrackBitcoinTx track = new TrackBitcoinTx(Stub(Upstreams)) TrackBitcoinTx track = new TrackBitcoinTx(Stub(MultistreamHolder))
def txid = "69cd44d7c641db82e69824523c7ac0c5c1e5628f025474529cf5ffe64527efc9" def txid = "69cd44d7c641db82e69824523c7ac0c5c1e5628f025474529cf5ffe64527efc9"
BitcoinChainUpstreams upstream = Mock(BitcoinChainUpstreams) { BitcoinMultistream upstream = Mock(BitcoinMultistream) {
_ * getReader() >> Mock(BitcoinReader) { _ * getReader() >> Mock(BitcoinReader) {
1 * getTx(txid) >> Mono.just([ 1 * getTx(txid) >> Mono.just([
txid: txid txid: txid
@@ -114,9 +111,9 @@ class TrackBitcoinTxSpec extends Specification {
def "loadExiting() returns block if mined"() { def "loadExiting() returns block if mined"() {
setup: setup:
TrackBitcoinTx track = new TrackBitcoinTx(Stub(Upstreams)) TrackBitcoinTx track = new TrackBitcoinTx(Stub(MultistreamHolder))
def txid = "69cd44d7c641db82e69824523c7ac0c5c1e5628f025474529cf5ffe64527efc9" def txid = "69cd44d7c641db82e69824523c7ac0c5c1e5628f025474529cf5ffe64527efc9"
BitcoinChainUpstreams upstream = Mock(BitcoinChainUpstreams) { BitcoinMultistream upstream = Mock(BitcoinMultistream) {
_ * getReader() >> Mock(BitcoinReader) { _ * getReader() >> Mock(BitcoinReader) {
1 * getTx(txid) >> Mono.just([ 1 * getTx(txid) >> Mono.just([
txid : txid, txid : txid,
@@ -141,7 +138,7 @@ class TrackBitcoinTxSpec extends Specification {
def "Goes with confirmations"() { def "Goes with confirmations"() {
setup: setup:
TrackBitcoinTx track = new TrackBitcoinTx(Stub(Upstreams)) TrackBitcoinTx track = new TrackBitcoinTx(Stub(MultistreamHolder))
def txid = "69cd44d7c641db82e69824523c7ac0c5c1e5628f025474529cf5ffe64527efc9" def txid = "69cd44d7c641db82e69824523c7ac0c5c1e5628f025474529cf5ffe64527efc9"
// start with the current block // start with the current block
def next = Flux.fromIterable([10, 12, 13, 14, 15]).map { h -> def next = Flux.fromIterable([10, 12, 13, 14, 15]).map { h ->
@@ -150,7 +147,7 @@ class TrackBitcoinTxSpec extends Specification {
Head head = Mock(Head) { Head head = Mock(Head) {
1 * getFlux() >> next 1 * getFlux() >> next
} }
BitcoinChainUpstreams upstream = Mock(BitcoinChainUpstreams) { BitcoinMultistream upstream = Mock(BitcoinMultistream) {
1 * getHead() >> head 1 * getHead() >> head
} }
def status = new TrackBitcoinTx.TxStatus( def status = new TrackBitcoinTx.TxStatus(
@@ -172,7 +169,7 @@ class TrackBitcoinTxSpec extends Specification {
def "Wait until mined"() { def "Wait until mined"() {
setup: setup:
TrackBitcoinTx track = new TrackBitcoinTx(Stub(Upstreams)) TrackBitcoinTx track = new TrackBitcoinTx(Stub(MultistreamHolder))
def txid = "69cd44d7c641db82e69824523c7ac0c5c1e5628f025474529cf5ffe64527efc9" def txid = "69cd44d7c641db82e69824523c7ac0c5c1e5628f025474529cf5ffe64527efc9"
// start with the current block // start with the current block
def next = Flux.fromIterable([10, 12, 13]).map { h -> def next = Flux.fromIterable([10, 12, 13]).map { h ->
@@ -196,7 +193,7 @@ class TrackBitcoinTxSpec extends Specification {
]) ])
] ]
} }
BitcoinChainUpstreams upstream = Mock(BitcoinChainUpstreams) { BitcoinMultistream upstream = Mock(BitcoinMultistream) {
1 * getHead() >> head 1 * getHead() >> head
_ * getReader() >> api _ * getReader() >> api
} }
@@ -215,7 +212,7 @@ class TrackBitcoinTxSpec extends Specification {
def "Check mempool until found"() { def "Check mempool until found"() {
setup: setup:
TrackBitcoinTx track = new TrackBitcoinTx(Stub(Upstreams)) TrackBitcoinTx track = new TrackBitcoinTx(Stub(MultistreamHolder))
def txid = "69cd44d7c641db82e69824523c7ac0c5c1e5628f025474529cf5ffe64527efc9" def txid = "69cd44d7c641db82e69824523c7ac0c5c1e5628f025474529cf5ffe64527efc9"
Head head = Mock(Head) { Head head = Mock(Head) {
@@ -235,7 +232,7 @@ class TrackBitcoinTxSpec extends Specification {
]) ])
_ * getMempool() >> mempoolAccess _ * getMempool() >> mempoolAccess
} }
BitcoinChainUpstreams upstream = Mock(BitcoinChainUpstreams) { BitcoinMultistream upstream = Mock(BitcoinMultistream) {
_ * getHead() >> head _ * getHead() >> head
_ * getReader() >> api _ * getReader() >> api
} }
@@ -256,7 +253,7 @@ class TrackBitcoinTxSpec extends Specification {
def "Subscribe to an existing tx"() { def "Subscribe to an existing tx"() {
setup: setup:
TrackBitcoinTx track = new TrackBitcoinTx(Stub(Upstreams)) TrackBitcoinTx track = new TrackBitcoinTx(Stub(MultistreamHolder))
def txid = "69cd44d7c641db82e69824523c7ac0c5c1e5628f025474529cf5ffe64527efc9" def txid = "69cd44d7c641db82e69824523c7ac0c5c1e5628f025474529cf5ffe64527efc9"
BitcoinReader api = Mock(BitcoinReader) { BitcoinReader api = Mock(BitcoinReader) {
_ * getTx(txid) >> Mono.just([ _ * getTx(txid) >> Mono.just([
@@ -276,7 +273,7 @@ class TrackBitcoinTxSpec extends Specification {
Head head = Mock(Head) { Head head = Mock(Head) {
_ * getFlux() >> next _ * getFlux() >> next
} }
BitcoinChainUpstreams upstream = Mock(BitcoinChainUpstreams) { BitcoinMultistream upstream = Mock(BitcoinMultistream) {
_ * getReader() >> api _ * getReader() >> api
_ * getHead() >> head _ * getHead() >> head
} }

View File

@@ -19,21 +19,12 @@ package io.emeraldpay.dshackle.rpc
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.dshackle.data.BlockContainer import io.emeraldpay.dshackle.data.BlockContainer
import io.emeraldpay.dshackle.reader.Reader
import io.emeraldpay.dshackle.test.TestingCommons import io.emeraldpay.dshackle.test.TestingCommons
import io.emeraldpay.dshackle.test.UpstreamsMock import io.emeraldpay.dshackle.test.MultistreamHolderMock
import io.emeraldpay.dshackle.upstream.Upstreams import io.emeraldpay.dshackle.upstream.MultistreamHolder
import io.emeraldpay.dshackle.upstream.ethereum.EthereumReader
import io.emeraldpay.grpc.Chain import io.emeraldpay.grpc.Chain
import io.infinitape.etherjar.domain.Address
import io.infinitape.etherjar.domain.BlockHash import io.infinitape.etherjar.domain.BlockHash
import io.infinitape.etherjar.rpc.ReactorRpcClient
import io.infinitape.etherjar.rpc.RpcCall
import io.infinitape.etherjar.rpc.json.BlockJson import io.infinitape.etherjar.rpc.json.BlockJson
import reactor.core.publisher.Flux
import reactor.core.publisher.Mono
import reactor.core.publisher.TopicProcessor
import reactor.core.scheduler.Schedulers
import reactor.test.StepVerifier import reactor.test.StepVerifier
import spock.lang.Specification import spock.lang.Specification
@@ -66,7 +57,7 @@ class TrackEthereumAddressSpec extends Specification {
def apiMock = TestingCommons.api() def apiMock = TestingCommons.api()
def upstreamMock = TestingCommons.upstream(apiMock) def upstreamMock = TestingCommons.upstream(apiMock)
Upstreams upstreams = new UpstreamsMock(Chain.ETHEREUM, upstreamMock) MultistreamHolder upstreams = new MultistreamHolderMock(Chain.ETHEREUM, upstreamMock)
TrackEthereumAddress trackAddress = new TrackEthereumAddress(upstreams) TrackEthereumAddress trackAddress = new TrackEthereumAddress(upstreams)
apiMock.answer("eth_getBalance", ["0xe2c8fa8120d813cd0b5e6add120295bf20cfa09f", "latest"], "0x499602D2") apiMock.answer("eth_getBalance", ["0xe2c8fa8120d813cd0b5e6add120295bf20cfa09f", "latest"], "0x499602D2")
@@ -106,7 +97,7 @@ class TrackEthereumAddressSpec extends Specification {
def apiMock = TestingCommons.api() def apiMock = TestingCommons.api()
def upstreamMock = TestingCommons.upstream(apiMock) def upstreamMock = TestingCommons.upstream(apiMock)
Upstreams upstreams = new UpstreamsMock(Chain.ETHEREUM, upstreamMock) MultistreamHolder upstreams = new MultistreamHolderMock(Chain.ETHEREUM, upstreamMock)
TrackEthereumAddress trackAddress = new TrackEthereumAddress(upstreams) TrackEthereumAddress trackAddress = new TrackEthereumAddress(upstreams)
apiMock.answerOnce("eth_getBalance", ["0xe2c8fa8120d813cd0b5e6add120295bf20cfa09f", "latest"], "0x499602D2") apiMock.answerOnce("eth_getBalance", ["0xe2c8fa8120d813cd0b5e6add120295bf20cfa09f", "latest"], "0x499602D2")

View File

@@ -23,10 +23,10 @@ import io.emeraldpay.dshackle.data.BlockContainer
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.test.TestingCommons import io.emeraldpay.dshackle.test.TestingCommons
import io.emeraldpay.dshackle.test.UpstreamsMock import io.emeraldpay.dshackle.test.MultistreamHolderMock
import io.emeraldpay.dshackle.upstream.Head import io.emeraldpay.dshackle.upstream.Head
import io.emeraldpay.dshackle.upstream.Upstreams import io.emeraldpay.dshackle.upstream.MultistreamHolder
import io.emeraldpay.dshackle.upstream.ethereum.EthereumChainUpstream import io.emeraldpay.dshackle.upstream.ethereum.EthereumMultistream
import io.emeraldpay.grpc.Chain import io.emeraldpay.grpc.Chain
import io.infinitape.etherjar.domain.BlockHash import io.infinitape.etherjar.domain.BlockHash
import io.infinitape.etherjar.domain.TransactionId import io.infinitape.etherjar.domain.TransactionId
@@ -98,7 +98,7 @@ class TrackEthereumTxSpec extends Specification {
def apiMock = TestingCommons.api() def apiMock = TestingCommons.api()
def upstreamMock = TestingCommons.upstream(apiMock) def upstreamMock = TestingCommons.upstream(apiMock)
Upstreams upstreams = new UpstreamsMock(Chain.ETHEREUM, upstreamMock) MultistreamHolder upstreams = new MultistreamHolderMock(Chain.ETHEREUM, upstreamMock)
TrackEthereumTx trackTx = new TrackEthereumTx(upstreams) TrackEthereumTx trackTx = new TrackEthereumTx(upstreams)
apiMock.answer("eth_getTransactionByHash", [txId], txJson) apiMock.answer("eth_getTransactionByHash", [txId], txJson)
@@ -118,8 +118,8 @@ class TrackEthereumTxSpec extends Specification {
setup: setup:
def apiMock = TestingCommons.api() def apiMock = TestingCommons.api()
def upstreamMock = TestingCommons.upstream(apiMock) def upstreamMock = TestingCommons.upstream(apiMock)
Upstreams upstreams = new UpstreamsMock(Chain.ETHEREUM, upstreamMock) MultistreamHolder upstreams = new MultistreamHolderMock(Chain.ETHEREUM, upstreamMock)
((EthereumChainUpstream) upstreams.getUpstream(Chain.ETHEREUM)).head = Mock(Head) { ((EthereumMultistream) upstreams.getUpstream(Chain.ETHEREUM)).head = Mock(Head) {
_ * getFlux() >> Flux.empty() _ * getFlux() >> Flux.empty()
} }
TrackEthereumTx trackTx = new TrackEthereumTx(upstreams) TrackEthereumTx trackTx = new TrackEthereumTx(upstreams)
@@ -131,7 +131,7 @@ class TrackEthereumTxSpec extends Specification {
when: when:
def tx = new TrackEthereumTx.TxDetails(Chain.ETHEREUM, Instant.now(), TransactionId.from(txId), 6) def tx = new TrackEthereumTx.TxDetails(Chain.ETHEREUM, Instant.now(), TransactionId.from(txId), 6)
def act = StepVerifier.withVirtualTime( def act = StepVerifier.withVirtualTime(
{ trackTx.subscribe(tx, upstreams.getUpstream(Chain.ETHEREUM).cast(EthereumChainUpstream)) }, { trackTx.subscribe(tx, upstreams.getUpstream(Chain.ETHEREUM).cast(EthereumMultistream)) },
{ scheduler }, { scheduler },
5) 5)
@@ -168,7 +168,7 @@ class TrackEthereumTxSpec extends Specification {
def apiMock = TestingCommons.api() def apiMock = TestingCommons.api()
def upstreamMock = TestingCommons.upstream(apiMock) def upstreamMock = TestingCommons.upstream(apiMock)
Upstreams upstreams = new UpstreamsMock(Chain.ETHEREUM, upstreamMock) MultistreamHolder upstreams = new MultistreamHolderMock(Chain.ETHEREUM, upstreamMock)
TrackEthereumTx trackTx = new TrackEthereumTx(upstreams) TrackEthereumTx trackTx = new TrackEthereumTx(upstreams)
def scheduler = VirtualTimeScheduler.create(true) def scheduler = VirtualTimeScheduler.create(true)
trackTx.scheduler = scheduler trackTx.scheduler = scheduler
@@ -193,7 +193,7 @@ class TrackEthereumTxSpec extends Specification {
setup: setup:
def apiMock = TestingCommons.api() def apiMock = TestingCommons.api()
def upstreamMock = TestingCommons.upstream(apiMock) def upstreamMock = TestingCommons.upstream(apiMock)
Upstreams upstreams = new UpstreamsMock(Chain.ETHEREUM, upstreamMock) MultistreamHolder upstreams = new MultistreamHolderMock(Chain.ETHEREUM, upstreamMock)
TrackEthereumTx trackTx = new TrackEthereumTx(upstreams) TrackEthereumTx trackTx = new TrackEthereumTx(upstreams)
def tx = new TrackEthereumTx.TxDetails(Chain.ETHEREUM, Instant.now(), TransactionId.from(txId), 6) def tx = new TrackEthereumTx.TxDetails(Chain.ETHEREUM, Instant.now(), TransactionId.from(txId), 6)
@@ -215,7 +215,7 @@ class TrackEthereumTxSpec extends Specification {
setup: setup:
def apiMock = TestingCommons.api() def apiMock = TestingCommons.api()
def upstreamMock = TestingCommons.upstream(apiMock) def upstreamMock = TestingCommons.upstream(apiMock)
Upstreams upstreams = new UpstreamsMock(Chain.ETHEREUM, upstreamMock) MultistreamHolder upstreams = new MultistreamHolderMock(Chain.ETHEREUM, upstreamMock)
TrackEthereumTx trackTx = new TrackEthereumTx(upstreams) TrackEthereumTx trackTx = new TrackEthereumTx(upstreams)
def tx = new TrackEthereumTx.TxDetails(Chain.ETHEREUM, Instant.now(), TransactionId.from(txId), 6) def tx = new TrackEthereumTx.TxDetails(Chain.ETHEREUM, Instant.now(), TransactionId.from(txId), 6)
@@ -288,7 +288,7 @@ class TrackEthereumTxSpec extends Specification {
def apiMock = TestingCommons.api() def apiMock = TestingCommons.api()
def upstreamMock = TestingCommons.upstream(apiMock) def upstreamMock = TestingCommons.upstream(apiMock)
Upstreams upstreams = new UpstreamsMock(Chain.ETHEREUM, upstreamMock) MultistreamHolder upstreams = new MultistreamHolderMock(Chain.ETHEREUM, upstreamMock)
TrackEthereumTx trackTx = new TrackEthereumTx(upstreams) TrackEthereumTx trackTx = new TrackEthereumTx(upstreams)
apiMock.answerOnce("eth_getTransactionByHash", [txId], null) apiMock.answerOnce("eth_getTransactionByHash", [txId], null)

View File

@@ -16,47 +16,47 @@
*/ */
package io.emeraldpay.dshackle.test package io.emeraldpay.dshackle.test
import com.fasterxml.jackson.databind.ObjectMapper
import io.emeraldpay.dshackle.BlockchainType import io.emeraldpay.dshackle.BlockchainType
import io.emeraldpay.dshackle.cache.Caches import io.emeraldpay.dshackle.cache.Caches
import io.emeraldpay.dshackle.upstream.AggregatedUpstream import io.emeraldpay.dshackle.upstream.Multistream
import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinChainUpstreams import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinMultistream
import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinUpstream import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinUpstream
import io.emeraldpay.dshackle.upstream.calls.DefaultEthereumMethods import io.emeraldpay.dshackle.upstream.calls.DefaultEthereumMethods
import io.emeraldpay.dshackle.upstream.Upstream import io.emeraldpay.dshackle.upstream.Upstream
import io.emeraldpay.dshackle.upstream.Upstreams import io.emeraldpay.dshackle.upstream.MultistreamHolder
import io.emeraldpay.dshackle.upstream.ethereum.EthereumChainUpstream import io.emeraldpay.dshackle.upstream.ethereum.EthereumMultistream
import io.emeraldpay.dshackle.upstream.ethereum.EthereumReader import io.emeraldpay.dshackle.upstream.ethereum.EthereumReader
import io.emeraldpay.dshackle.upstream.ethereum.EthereumUpstream import io.emeraldpay.dshackle.upstream.ethereum.EthereumUpstream
import io.emeraldpay.grpc.Chain import io.emeraldpay.grpc.Chain
import org.jetbrains.annotations.NotNull import org.jetbrains.annotations.NotNull
import reactor.core.publisher.Flux import reactor.core.publisher.Flux
class UpstreamsMock implements Upstreams { class MultistreamHolderMock implements MultistreamHolder {
private Map<Chain, DefaultEthereumMethods> target = [:] private Map<Chain, DefaultEthereumMethods> target = [:]
private Map<Chain, AggregatedUpstream> upstreams = [:] private Map<Chain, Multistream> upstreams = [:]
UpstreamsMock(Chain chain, Upstream up) { MultistreamHolderMock(Chain chain, Upstream up) {
addUpstream(chain, up) addUpstream(chain, up)
} }
AggregatedUpstream addUpstream(@NotNull Chain chain, @NotNull Upstream up) { Multistream addUpstream(@NotNull Chain chain, @NotNull Upstream up) {
if (!upstreams.containsKey(chain)) { if (!upstreams.containsKey(chain)) {
if (BlockchainType.fromBlockchain(chain) == BlockchainType.ETHEREUM) { if (BlockchainType.fromBlockchain(chain) == BlockchainType.ETHEREUM) {
if (up instanceof EthereumChainUpstream) { if (up instanceof EthereumMultistream) {
upstreams[chain] = up upstreams[chain] = up
} else if (up instanceof EthereumUpstream) { } else if (up instanceof EthereumUpstream) {
upstreams[chain] = new EthereumChainUpstreamMock(chain, [up as EthereumUpstream], Caches.default(TestingCommons.objectMapper())) upstreams[chain] = new EthereumMultistreamMock(chain, [up as EthereumUpstream], Caches.default(TestingCommons.objectMapper()))
} else { } else {
throw new IllegalArgumentException("Unsupported upstream type ${up.class}") throw new IllegalArgumentException("Unsupported upstream type ${up.class}")
} }
upstreams[chain].start() upstreams[chain].start()
} else if (BlockchainType.fromBlockchain(chain) == BlockchainType.BITCOIN) { } else if (BlockchainType.fromBlockchain(chain) == BlockchainType.BITCOIN) {
if (up instanceof BitcoinChainUpstreams) { if (up instanceof BitcoinMultistream) {
upstreams[chain] = up upstreams[chain] = up
} else if (up instanceof BitcoinUpstream) { } else if (up instanceof BitcoinUpstream) {
upstreams[chain] = new BitcoinChainUpstreams(chain, [up as BitcoinUpstream], Caches.default(TestingCommons.objectMapper()), TestingCommons.objectMapper()) upstreams[chain] = new BitcoinMultistream(chain, [up as BitcoinUpstream], Caches.default(TestingCommons.objectMapper()), TestingCommons.objectMapper())
} else { } else {
throw new IllegalArgumentException("Unsupported upstream type ${up.class}") throw new IllegalArgumentException("Unsupported upstream type ${up.class}")
} }
@@ -69,7 +69,7 @@ class UpstreamsMock implements Upstreams {
} }
@Override @Override
AggregatedUpstream getUpstream(@NotNull Chain chain) { Multistream getUpstream(@NotNull Chain chain) {
return upstreams[chain] return upstreams[chain]
} }
@@ -97,11 +97,11 @@ class UpstreamsMock implements Upstreams {
return upstreams.containsKey(chain) return upstreams.containsKey(chain)
} }
static class EthereumChainUpstreamMock extends EthereumChainUpstream { static class EthereumMultistreamMock extends EthereumMultistream {
EthereumReader customReader = null EthereumReader customReader = null
EthereumChainUpstreamMock(@NotNull Chain chain, @NotNull List<EthereumUpstream> upstreams, @NotNull Caches caches) { EthereumMultistreamMock(@NotNull Chain chain, @NotNull List<EthereumUpstream> upstreams, @NotNull Caches caches) {
super(chain, upstreams, caches, TestingCommons.objectMapper()) super(chain, upstreams, caches, TestingCommons.objectMapper())
} }

View File

@@ -25,9 +25,9 @@ import io.emeraldpay.dshackle.cache.Caches
import io.emeraldpay.dshackle.cache.CachesFactory import io.emeraldpay.dshackle.cache.CachesFactory
import io.emeraldpay.dshackle.config.CacheConfig import io.emeraldpay.dshackle.config.CacheConfig
import io.emeraldpay.dshackle.reader.Reader import io.emeraldpay.dshackle.reader.Reader
import io.emeraldpay.dshackle.upstream.AggregatedUpstream import io.emeraldpay.dshackle.upstream.Multistream
import io.emeraldpay.dshackle.upstream.calls.DirectCallMethods import io.emeraldpay.dshackle.upstream.calls.DirectCallMethods
import io.emeraldpay.dshackle.upstream.ethereum.EthereumChainUpstream import io.emeraldpay.dshackle.upstream.ethereum.EthereumMultistream
import io.emeraldpay.dshackle.upstream.ethereum.EthereumUpstream import io.emeraldpay.dshackle.upstream.ethereum.EthereumUpstream
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
@@ -71,12 +71,12 @@ class TestingCommons {
return new EthereumUpstreamMock(Chain.ETHEREUM, api, new DirectCallMethods(methods)) return new EthereumUpstreamMock(Chain.ETHEREUM, api, new DirectCallMethods(methods))
} }
static AggregatedUpstream aggregatedUpstream(Reader<JsonRpcRequest, JsonRpcResponse> api) { static Multistream aggregatedUpstream(Reader<JsonRpcRequest, JsonRpcResponse> api) {
return aggregatedUpstream(upstream(api)) return aggregatedUpstream(upstream(api))
} }
static AggregatedUpstream aggregatedUpstream(EthereumUpstream up) { static Multistream aggregatedUpstream(EthereumUpstream up) {
return new EthereumChainUpstream(Chain.ETHEREUM, [up], Caches.default(objectMapper()), objectMapper()) return new EthereumMultistream(Chain.ETHEREUM, [up], Caches.default(objectMapper()), objectMapper())
} }
static CachesFactory emptyCaches() { static CachesFactory emptyCaches() {

View File

@@ -19,14 +19,13 @@ import io.emeraldpay.dshackle.startup.UpstreamChange
import io.emeraldpay.dshackle.test.EthereumUpstreamMock import io.emeraldpay.dshackle.test.EthereumUpstreamMock
import io.emeraldpay.dshackle.test.TestingCommons import io.emeraldpay.dshackle.test.TestingCommons
import io.emeraldpay.grpc.Chain import io.emeraldpay.grpc.Chain
import io.infinitape.etherjar.rpc.ReactorRpcClient
import spock.lang.Specification import spock.lang.Specification
class CurrentUpstreamsSpec extends Specification { class CurrentMultistreamHolderSpec extends Specification {
def "add upstream"() { def "add upstream"() {
setup: setup:
def current = new CurrentUpstreams(TestingCommons.objectMapper(), TestingCommons.emptyCaches()) def current = new CurrentMultistreamHolder(TestingCommons.objectMapper(), TestingCommons.emptyCaches())
def up = new EthereumUpstreamMock("test", Chain.ETHEREUM, TestingCommons.api()) def up = new EthereumUpstreamMock("test", Chain.ETHEREUM, TestingCommons.api())
when: when:
current.update(new UpstreamChange(Chain.ETHEREUM, up, UpstreamChange.ChangeType.ADDED)) current.update(new UpstreamChange(Chain.ETHEREUM, up, UpstreamChange.ChangeType.ADDED))
@@ -37,7 +36,7 @@ class CurrentUpstreamsSpec extends Specification {
def "add multiple upstreams"() { def "add multiple upstreams"() {
setup: setup:
def current = new CurrentUpstreams(TestingCommons.objectMapper(), TestingCommons.emptyCaches()) def current = new CurrentMultistreamHolder(TestingCommons.objectMapper(), TestingCommons.emptyCaches())
def up1 = new EthereumUpstreamMock("test1", Chain.ETHEREUM, TestingCommons.api()) def up1 = new EthereumUpstreamMock("test1", Chain.ETHEREUM, TestingCommons.api())
def up2 = new EthereumUpstreamMock("test2", Chain.ETHEREUM_CLASSIC, TestingCommons.api()) def up2 = new EthereumUpstreamMock("test2", Chain.ETHEREUM_CLASSIC, TestingCommons.api())
def up3 = new EthereumUpstreamMock("test3", Chain.ETHEREUM, TestingCommons.api()) def up3 = new EthereumUpstreamMock("test3", Chain.ETHEREUM, TestingCommons.api())
@@ -53,7 +52,7 @@ class CurrentUpstreamsSpec extends Specification {
def "remove upstream"() { def "remove upstream"() {
setup: setup:
def current = new CurrentUpstreams(TestingCommons.objectMapper(), TestingCommons.emptyCaches()) def current = new CurrentMultistreamHolder(TestingCommons.objectMapper(), TestingCommons.emptyCaches())
def up1 = new EthereumUpstreamMock("test1", Chain.ETHEREUM, TestingCommons.api()) def up1 = new EthereumUpstreamMock("test1", Chain.ETHEREUM, TestingCommons.api())
def up2 = new EthereumUpstreamMock("test2", Chain.ETHEREUM_CLASSIC, TestingCommons.api()) def up2 = new EthereumUpstreamMock("test2", Chain.ETHEREUM_CLASSIC, TestingCommons.api())
def up3 = new EthereumUpstreamMock("test3", Chain.ETHEREUM, TestingCommons.api()) def up3 = new EthereumUpstreamMock("test3", Chain.ETHEREUM, TestingCommons.api())
@@ -71,7 +70,7 @@ class CurrentUpstreamsSpec extends Specification {
def "available after adding"() { def "available after adding"() {
setup: setup:
def current = new CurrentUpstreams(TestingCommons.objectMapper(), TestingCommons.emptyCaches()) def current = new CurrentMultistreamHolder(TestingCommons.objectMapper(), TestingCommons.emptyCaches())
def up1 = new EthereumUpstreamMock("test1", Chain.ETHEREUM, TestingCommons.api()) def up1 = new EthereumUpstreamMock("test1", Chain.ETHEREUM, TestingCommons.api())
when: when:

View File

@@ -21,17 +21,17 @@ import io.emeraldpay.dshackle.quorum.AlwaysQuorum
import io.emeraldpay.dshackle.test.EthereumUpstreamMock import io.emeraldpay.dshackle.test.EthereumUpstreamMock
import io.emeraldpay.dshackle.test.TestingCommons import io.emeraldpay.dshackle.test.TestingCommons
import io.emeraldpay.dshackle.upstream.calls.DirectCallMethods import io.emeraldpay.dshackle.upstream.calls.DirectCallMethods
import io.emeraldpay.dshackle.upstream.ethereum.EthereumChainUpstream import io.emeraldpay.dshackle.upstream.ethereum.EthereumMultistream
import io.emeraldpay.grpc.Chain import io.emeraldpay.grpc.Chain
import spock.lang.Specification import spock.lang.Specification
class AggregatedUpstreamSpec extends Specification { class MultistreamSpec extends Specification {
def "Aggregates methods"() { def "Aggregates methods"() {
setup: setup:
def up1 = new EthereumUpstreamMock("test1", Chain.ETHEREUM, TestingCommons.api(), new DirectCallMethods(["eth_test1", "eth_test2"])) def up1 = new EthereumUpstreamMock("test1", Chain.ETHEREUM, TestingCommons.api(), new DirectCallMethods(["eth_test1", "eth_test2"]))
def up2 = new EthereumUpstreamMock("test1", Chain.ETHEREUM, TestingCommons.api(), new DirectCallMethods(["eth_test2", "eth_test3"])) def up2 = new EthereumUpstreamMock("test1", Chain.ETHEREUM, TestingCommons.api(), new DirectCallMethods(["eth_test2", "eth_test3"]))
def aggr = new EthereumChainUpstream(Chain.ETHEREUM, [up1, up2], Caches.default(TestingCommons.objectMapper()), TestingCommons.objectMapper()) def aggr = new EthereumMultistream(Chain.ETHEREUM, [up1, up2], Caches.default(TestingCommons.objectMapper()), TestingCommons.objectMapper())
when: when:
aggr.onUpstreamsUpdated() aggr.onUpstreamsUpdated()
def act = aggr.getMethods() def act = aggr.getMethods()

View File

@@ -17,26 +17,18 @@ package io.emeraldpay.dshackle.upstream.ethereum
import io.emeraldpay.dshackle.cache.BlocksMemCache import io.emeraldpay.dshackle.cache.BlocksMemCache
import io.emeraldpay.dshackle.cache.Caches import io.emeraldpay.dshackle.cache.Caches
import io.emeraldpay.dshackle.cache.HeightCache
import io.emeraldpay.dshackle.cache.TxMemCache import io.emeraldpay.dshackle.cache.TxMemCache
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
import io.emeraldpay.dshackle.data.TxId
import io.emeraldpay.dshackle.test.EthereumUpstreamMock import io.emeraldpay.dshackle.test.EthereumUpstreamMock
import io.emeraldpay.dshackle.test.TestingCommons import io.emeraldpay.dshackle.test.TestingCommons
import io.emeraldpay.dshackle.test.UpstreamsMock import io.emeraldpay.dshackle.upstream.Multistream
import io.emeraldpay.dshackle.upstream.AggregatedUpstream
import io.emeraldpay.dshackle.upstream.Head
import io.emeraldpay.dshackle.upstream.Upstream
import io.emeraldpay.grpc.Chain import io.emeraldpay.grpc.Chain
import io.infinitape.etherjar.domain.Address import io.infinitape.etherjar.domain.Address
import io.infinitape.etherjar.domain.BlockHash import io.infinitape.etherjar.domain.BlockHash
import io.infinitape.etherjar.domain.TransactionId import io.infinitape.etherjar.domain.TransactionId
import io.infinitape.etherjar.domain.Wei import io.infinitape.etherjar.domain.Wei
import io.infinitape.etherjar.rpc.ReactorRpcClient
import io.infinitape.etherjar.rpc.RpcException
import io.infinitape.etherjar.rpc.RpcResponseError
import io.infinitape.etherjar.rpc.json.BlockJson import io.infinitape.etherjar.rpc.json.BlockJson
import io.infinitape.etherjar.rpc.json.TransactionJson import io.infinitape.etherjar.rpc.json.TransactionJson
import io.infinitape.etherjar.rpc.json.TransactionRefJson import io.infinitape.etherjar.rpc.json.TransactionRefJson
@@ -44,7 +36,6 @@ import reactor.core.publisher.Mono
import spock.lang.Specification import spock.lang.Specification
import java.time.Instant import java.time.Instant
import java.time.temporal.ChronoUnit
class EthereumReaderSpec extends Specification { class EthereumReaderSpec extends Specification {
@@ -73,7 +64,7 @@ class EthereumReaderSpec extends Specification {
.setBlockByHash(memCache) .setBlockByHash(memCache)
.setObjectMapper(TestingCommons.objectMapper()) .setObjectMapper(TestingCommons.objectMapper())
.build() .build()
def reader = new EthereumReader(Stub(AggregatedUpstream), caches, TestingCommons.objectMapper()) def reader = new EthereumReader(Stub(Multistream), caches, TestingCommons.objectMapper())
when: when:
def act = reader.blocksById().read(blockId).block() def act = reader.blocksById().read(blockId).block()
@@ -135,7 +126,7 @@ class EthereumReaderSpec extends Specification {
.setBlockByHash(memCache) .setBlockByHash(memCache)
.setObjectMapper(TestingCommons.objectMapper()) .setObjectMapper(TestingCommons.objectMapper())
.build() .build()
def reader = new EthereumReader(Stub(AggregatedUpstream), caches, TestingCommons.objectMapper()) def reader = new EthereumReader(Stub(Multistream), caches, TestingCommons.objectMapper())
when: when:
def act = reader.blocksByHash().read(blockJson.hash).block() def act = reader.blocksByHash().read(blockJson.hash).block()
@@ -174,7 +165,7 @@ class EthereumReaderSpec extends Specification {
.setTxByHash(memCache) .setTxByHash(memCache)
.setObjectMapper(TestingCommons.objectMapper()) .setObjectMapper(TestingCommons.objectMapper())
.build() .build()
def reader = new EthereumReader(Stub(AggregatedUpstream), caches, TestingCommons.objectMapper()) def reader = new EthereumReader(Stub(Multistream), caches, TestingCommons.objectMapper())
when: when:
def act = reader.txByHash().read(txJson.hash).block() def act = reader.txByHash().read(txJson.hash).block()

View File

@@ -29,8 +29,6 @@ import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcGrpcClient
import io.emeraldpay.grpc.Chain import io.emeraldpay.grpc.Chain
import io.grpc.stub.StreamObserver import io.grpc.stub.StreamObserver
import io.infinitape.etherjar.domain.BlockHash import io.infinitape.etherjar.domain.BlockHash
import io.infinitape.etherjar.rpc.ReactorRpcClient
import io.infinitape.etherjar.rpc.emerald.ReactorEmeraldClient
import io.infinitape.etherjar.rpc.json.BlockJson import io.infinitape.etherjar.rpc.json.BlockJson
import spock.lang.Specification import spock.lang.Specification