problem: doesn't return ERC20 balance
This commit is contained in:
@@ -21,5 +21,9 @@ import org.reactivestreams.Publisher
|
|||||||
interface ApiSource : Publisher<Upstream> {
|
interface ApiSource : Publisher<Upstream> {
|
||||||
|
|
||||||
fun resolve()
|
fun resolve()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Must be called before actual use, it spins off control flow of the API Source
|
||||||
|
*/
|
||||||
fun request(tries: Int)
|
fun request(tries: Int)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import kotlin.math.min
|
|||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
import kotlin.math.roundToLong
|
import kotlin.math.roundToLong
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
|
||||||
class FilteredApis(
|
class FilteredApis(
|
||||||
val chain: Chain,
|
val chain: Chain,
|
||||||
@@ -49,6 +50,8 @@ class FilteredApis(
|
|||||||
) : ApiSource {
|
) : ApiSource {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
private val log = LoggerFactory.getLogger(FilteredApis::class.java)
|
||||||
|
|
||||||
private const val DEFAULT_DELAY_STEP = 100
|
private const val DEFAULT_DELAY_STEP = 100
|
||||||
private const val MAX_WAIT_MILLIS = 5000L
|
private const val MAX_WAIT_MILLIS = 5000L
|
||||||
|
|
||||||
@@ -86,6 +89,7 @@ class FilteredApis(
|
|||||||
private val secondaryUpstreams: List<Upstream>
|
private val secondaryUpstreams: List<Upstream>
|
||||||
private val standardWithFallback: List<Upstream>
|
private val standardWithFallback: List<Upstream>
|
||||||
|
|
||||||
|
private var started = false
|
||||||
private val control = Sinks.many().unicast().onBackpressureBuffer<Boolean>()
|
private val control = Sinks.many().unicast().onBackpressureBuffer<Boolean>()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@@ -176,6 +180,12 @@ class FilteredApis(
|
|||||||
result.filter { up -> up.isAvailable() && matcher.matches(up) }
|
result.filter { up -> up.isAvailable() && matcher.matches(up) }
|
||||||
.zipWith(control.asFlux())
|
.zipWith(control.asFlux())
|
||||||
.map { it.t1 }
|
.map { it.t1 }
|
||||||
|
.doOnSubscribe {
|
||||||
|
if (!started) {
|
||||||
|
// in addition to subscription the FilteredAPI should use request() method to prepare the control flow
|
||||||
|
log.warn("API Source subscribed before preparing a request")
|
||||||
|
}
|
||||||
|
}
|
||||||
.subscribe(subscriber)
|
.subscribe(subscriber)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,6 +194,7 @@ class FilteredApis(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun request(tries: Int) {
|
override fun request(tries: Int) {
|
||||||
|
started = true
|
||||||
// TODO check the buffer size before submitting
|
// TODO check the buffer size before submitting
|
||||||
repeat(tries) {
|
repeat(tries) {
|
||||||
control.tryEmitNext(true)
|
control.tryEmitNext(true)
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package io.emeraldpay.dshackle.upstream.ethereum
|
package io.emeraldpay.dshackle.upstream.ethereum
|
||||||
|
|
||||||
|
import io.emeraldpay.dshackle.upstream.ApiSource
|
||||||
import io.emeraldpay.dshackle.upstream.Head
|
import io.emeraldpay.dshackle.upstream.Head
|
||||||
import io.emeraldpay.dshackle.upstream.Selector
|
import io.emeraldpay.dshackle.upstream.Selector
|
||||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
||||||
@@ -41,10 +42,18 @@ open class ERC20Balance {
|
|||||||
return upstreams
|
return upstreams
|
||||||
// use only up-to-date upstreams
|
// use only up-to-date upstreams
|
||||||
.getApiSource(Selector.HeightMatcher(upstreams.getHead().getCurrentHeight() ?: 0))
|
.getApiSource(Selector.HeightMatcher(upstreams.getHead().getCurrentHeight() ?: 0))
|
||||||
.let { Flux.from(it) }
|
.let { getBalance(it, token, address) }
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun getBalance(apis: ApiSource, token: ERC20Token, address: Address): Mono<BigInteger> {
|
||||||
|
apis.request(1)
|
||||||
|
return Flux.from(apis)
|
||||||
.flatMap {
|
.flatMap {
|
||||||
getBalance(it.cast(EthereumUpstream::class.java), token, address)
|
getBalance(it.cast(EthereumUpstream::class.java), token, address)
|
||||||
}
|
}
|
||||||
|
.doOnNext {
|
||||||
|
apis.resolve()
|
||||||
|
}
|
||||||
.next()
|
.next()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ package io.emeraldpay.dshackle.upstream.ethereum
|
|||||||
|
|
||||||
import io.emeraldpay.dshackle.test.EthereumUpstreamMock
|
import io.emeraldpay.dshackle.test.EthereumUpstreamMock
|
||||||
import io.emeraldpay.dshackle.test.ReaderMock
|
import io.emeraldpay.dshackle.test.ReaderMock
|
||||||
|
import io.emeraldpay.dshackle.upstream.ApiSource
|
||||||
|
import io.emeraldpay.dshackle.upstream.FilteredApis
|
||||||
|
import io.emeraldpay.dshackle.upstream.Selector
|
||||||
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.etherjar.domain.Address
|
import io.emeraldpay.etherjar.domain.Address
|
||||||
@@ -55,4 +58,34 @@ class ERC20BalanceSpec extends Specification {
|
|||||||
then:
|
then:
|
||||||
act.toLong() == 0x1f28d72868
|
act.toLong() == 0x1f28d72868
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def "Gets balance from api source"() {
|
||||||
|
setup:
|
||||||
|
ReaderMock api = new ReaderMock()
|
||||||
|
.with(
|
||||||
|
new JsonRpcRequest("eth_call", [
|
||||||
|
new TransactionCallJson().tap { json ->
|
||||||
|
json.setTo(Address.from("0x54EedeAC495271d0F6B175474E89094C44Da98b9"))
|
||||||
|
json.setData(HexData.from("0x70a0823100000000000000000000000016c15c65ad00b6dfbcc2cb8a7b6c2d0103a3883b"))
|
||||||
|
},
|
||||||
|
"latest"
|
||||||
|
]),
|
||||||
|
JsonRpcResponse.ok('"0x0000000000000000000000000000000000000000000000000000001f28d72868"')
|
||||||
|
)
|
||||||
|
|
||||||
|
EthereumUpstream upstream = new EthereumUpstreamMock(Chain.ETHEREUM, api)
|
||||||
|
ERC20Token token = new ERC20Token(Address.from("0x54EedeAC495271d0F6B175474E89094C44Da98b9"))
|
||||||
|
ERC20Balance query = new ERC20Balance()
|
||||||
|
|
||||||
|
ApiSource apiSource = new FilteredApis(
|
||||||
|
Chain.ETHEREUM, [upstream], Selector.empty
|
||||||
|
)
|
||||||
|
|
||||||
|
when:
|
||||||
|
def act = query.getBalance(apiSource, token, Address.from("0x16c15c65ad00b6dfbcc2cb8a7b6c2d0103a3883b"))
|
||||||
|
.block(Duration.ofSeconds(1))
|
||||||
|
|
||||||
|
then:
|
||||||
|
act.toLong() == 0x1f28d72868
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user