problem: bitcoin mempool can be queries too often

solution: introduce data access wrappers, in this case caching mempool state in memory
This commit is contained in:
Igor Artamonov
2020-04-27 00:05:02 -04:00
parent c9082b3cd0
commit bd58ba9774
15 changed files with 197 additions and 73 deletions

View File

@@ -9,7 +9,7 @@ import io.emeraldpay.dshackle.upstream.AggregatedUpstream
import io.emeraldpay.dshackle.upstream.Head
import io.emeraldpay.dshackle.upstream.Upstream
import io.emeraldpay.dshackle.upstream.Upstreams
import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinApi
import io.emeraldpay.dshackle.upstream.bitcoin.DirectBitcoinApi
import io.emeraldpay.grpc.Chain
import reactor.core.publisher.Flux
import reactor.core.publisher.Mono
@@ -201,7 +201,7 @@ class TrackBitcoinAddressSpec extends Specification {
def "Get update for a balance"() {
setup:
BitcoinApi api = Mock(BitcoinApi) {
DirectBitcoinApi api = Mock(DirectBitcoinApi) {
2 * executeAndResult(0, "listunspent", [], List) >>> [
Mono.just([]), Mono.just([[address: "1K7xkspJg7DDKNwzXgoRSDCUxiFsRegsSK", amount: 0.0123]])
]

View File

@@ -5,7 +5,10 @@ import io.emeraldpay.dshackle.data.BlockId
import io.emeraldpay.dshackle.upstream.Head
import io.emeraldpay.dshackle.upstream.Upstream
import io.emeraldpay.dshackle.upstream.Upstreams
import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinApi
import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinData
import io.emeraldpay.dshackle.upstream.bitcoin.DirectBitcoinApi
import io.emeraldpay.dshackle.upstream.bitcoin.BitcoinUpstream
import io.emeraldpay.dshackle.upstream.bitcoin.CachingMempoolData
import io.emeraldpay.grpc.Chain
import reactor.core.publisher.Flux
import reactor.core.publisher.Mono
@@ -20,14 +23,20 @@ class TrackBitcoinTxSpec extends Specification {
def "loadMempool() returns not found when not found"() {
setup:
TrackBitcoinTx track = new TrackBitcoinTx(Stub(Upstreams))
BitcoinApi api = Mock(BitcoinApi) {
1 * getMempool() >> Mono.just([
CachingMempoolData mempoolAccess = Mock(CachingMempoolData) {
1 * get() >> Mono.just([
"69cd44d7c641db82e69824523c7ac0c5c1e5628f025474529cf5ffe64527efc9",
"d296c6d47335a7f283574b06f1d6303b30ac75631e081ab128346a549ad93350"
])
}
BitcoinUpstream upstream = Mock(BitcoinUpstream) {
_ * getData() >> Mock(BitcoinData) {
_ * getMempool() >> mempoolAccess
}
}
when:
def act = track.loadMempool(api, "65ce58db064bd105b14dc76a0bce0df14653cf5263d22d17e78864cf272ee367")
def act = track.loadMempool(upstream, "65ce58db064bd105b14dc76a0bce0df14653cf5263d22d17e78864cf272ee367")
then:
StepVerifier.create(act)
@@ -41,14 +50,19 @@ class TrackBitcoinTxSpec extends Specification {
def "loadMempool() returns ok when found"() {
setup:
TrackBitcoinTx track = new TrackBitcoinTx(Stub(Upstreams))
BitcoinApi api = Mock(BitcoinApi) {
1 * getMempool() >> Mono.just([
CachingMempoolData mempoolAccess = Mock(CachingMempoolData) {
1 * get() >> Mono.just([
"69cd44d7c641db82e69824523c7ac0c5c1e5628f025474529cf5ffe64527efc9",
"d296c6d47335a7f283574b06f1d6303b30ac75631e081ab128346a549ad93350"
])
}
BitcoinUpstream upstream = Mock(BitcoinUpstream) {
_ * getData() >> Mock(BitcoinData) {
_ * getMempool() >> mempoolAccess
}
}
when:
def act = track.loadMempool(api, "69cd44d7c641db82e69824523c7ac0c5c1e5628f025474529cf5ffe64527efc9")
def act = track.loadMempool(upstream, "69cd44d7c641db82e69824523c7ac0c5c1e5628f025474529cf5ffe64527efc9")
then:
StepVerifier.create(act)
@@ -63,7 +77,7 @@ class TrackBitcoinTxSpec extends Specification {
setup:
TrackBitcoinTx track = new TrackBitcoinTx(Stub(Upstreams))
def txid = "69cd44d7c641db82e69824523c7ac0c5c1e5628f025474529cf5ffe64527efc9"
BitcoinApi api = Mock(BitcoinApi) {
DirectBitcoinApi api = Mock(DirectBitcoinApi) {
1 * getTx(txid) >> Mono.just([
txid: txid
])
@@ -84,7 +98,7 @@ class TrackBitcoinTxSpec extends Specification {
setup:
TrackBitcoinTx track = new TrackBitcoinTx(Stub(Upstreams))
def txid = "69cd44d7c641db82e69824523c7ac0c5c1e5628f025474529cf5ffe64527efc9"
BitcoinApi api = Mock(BitcoinApi) {
DirectBitcoinApi api = Mock(DirectBitcoinApi) {
1 * getTx(txid) >> Mono.just([
txid : txid,
blockhash: "0000000000000000000895d1b9d3898700e1deecc3b0e69f439aa77875e6042f",
@@ -116,7 +130,7 @@ class TrackBitcoinTxSpec extends Specification {
Head head = Mock(Head) {
1 * getFlux() >> next
}
Upstream upstream = Mock(Upstream) {
Upstream upstream = Mock(BitcoinUpstream) {
1 * getHead() >> head
}
def status = new TrackBitcoinTx.TxStatus(
@@ -147,7 +161,7 @@ class TrackBitcoinTxSpec extends Specification {
Head head = Mock(Head) {
1 * getFlux() >> next
}
BitcoinApi api = Mock(BitcoinApi) {
DirectBitcoinApi api = Mock(DirectBitcoinApi) {
3 * getTx(txid) >>> [
Mono.just([
txid: txid
@@ -162,7 +176,7 @@ class TrackBitcoinTxSpec extends Specification {
])
]
}
Upstream upstream = Mock(Upstream) {
Upstream upstream = Mock(BitcoinUpstream) {
1 * getHead() >> head
_ * getApi(_) >> Mono.just(api)
}
@@ -183,13 +197,7 @@ class TrackBitcoinTxSpec extends Specification {
setup:
TrackBitcoinTx track = new TrackBitcoinTx(Stub(Upstreams))
def txid = "69cd44d7c641db82e69824523c7ac0c5c1e5628f025474529cf5ffe64527efc9"
BitcoinApi api = Mock(BitcoinApi) {
4 * getMempool() >>> [
Mono.just([]),
Mono.just(["4523c7ac0c5c1e5628f025474529c69cd44d7c641db82e6982f5ffe64527efc9"]),
Mono.just(["4523c7ac0c5c1e5628f025474529c69cd44d7c641db82e6982f5ffe64527efc9", txid]),
Mono.just(["4523c7ac0c5c1e5628f025474529c69cd44d7c641db82e6982f5ffe64527efc9", txid]) //second call when started over
]
DirectBitcoinApi api = Mock(DirectBitcoinApi) {
1 * getTx(txid) >> Mono.just([
txid: txid
])
@@ -197,9 +205,20 @@ class TrackBitcoinTxSpec extends Specification {
Head head = Mock(Head) {
_ * getFlux() >> Flux.empty()
}
Upstream upstream = Mock(Upstream) {
CachingMempoolData mempoolAccess = Mock(CachingMempoolData) {
4 * get() >>> [
Mono.just([]),
Mono.just(["4523c7ac0c5c1e5628f025474529c69cd44d7c641db82e6982f5ffe64527efc9"]),
Mono.just(["4523c7ac0c5c1e5628f025474529c69cd44d7c641db82e6982f5ffe64527efc9", txid]),
Mono.just(["4523c7ac0c5c1e5628f025474529c69cd44d7c641db82e6982f5ffe64527efc9", txid]) //second call when started over
]
}
BitcoinUpstream upstream = Mock(BitcoinUpstream) {
_ * getApi(_) >> Mono.just(api)
_ * getHead() >> head
_ * getData() >> Mock(BitcoinData) {
_ * getMempool() >> mempoolAccess
}
}
when:
@@ -220,7 +239,7 @@ class TrackBitcoinTxSpec extends Specification {
setup:
TrackBitcoinTx track = new TrackBitcoinTx(Stub(Upstreams))
def txid = "69cd44d7c641db82e69824523c7ac0c5c1e5628f025474529cf5ffe64527efc9"
BitcoinApi api = Mock(BitcoinApi) {
DirectBitcoinApi api = Mock(DirectBitcoinApi) {
_ * getTx(txid) >> Mono.just([
txid : txid,
blockhash: "0000000000000000000895d1b9d3898700e1deecc3b0e69f439aa77875e6042f",
@@ -238,7 +257,7 @@ class TrackBitcoinTxSpec extends Specification {
Head head = Mock(Head) {
_ * getFlux() >> next
}
Upstream upstream = Mock(Upstream) {
BitcoinUpstream upstream = Mock(BitcoinUpstream) {
_ * getApi(_) >> Mono.just(api)
_ * getHead() >> head
}

View File

@@ -59,7 +59,7 @@ class BitcoinRpcHeadSpec extends Specification {
}
"""
BitcoinApi api = Mock(BitcoinApi) {
DirectBitcoinApi api = Mock(DirectBitcoinApi) {
_ * executeAndResult(_, "getbestblockhash", _, String) >>> [
Mono.just(hash1), Mono.just(hash1), Mono.just(hash2)
]

View File

@@ -10,14 +10,14 @@ import spock.lang.Specification
import java.time.Duration
class BitcoinApiSpec extends Specification {
class DirectBitcoinApiSpec extends Specification {
ClientAndServer mockServer
BitcoinApi api
DirectBitcoinApi api
def setup() {
mockServer = ClientAndServer.startClientAndServer(18332);
api = new BitcoinApi(
api = new DirectBitcoinApi(
new BitcoinRpcClient("localhost:18332", null),
TestingCommons.objectMapper(), new DefaultBitcoinMethods(TestingCommons.objectMapper())
)