Get FilterSync test working with cached bitcoind in chainTest project (#2952)

* Get FilterSync test working with cached bitcoind in chainTest project

* Small refactor to be DRY

* Fix docs

* Refactor ChainSyncTest to use 1 cached bitcoind, as a by product add ChainWithBitcoindNewestCachedUnitTest

* Remove unecessary mixin trait

* Fix missing ChainWithBitcoindNewestCachedUnitTest.afterAll()

* Reduce thread pool size for akka's internal dispatcher in unit tests from 2 -> 1. Same with the blocking dispatcher

* Add comment
This commit is contained in:
Chris Stewart 2021-04-26 07:41:30 -05:00 committed by GitHub
parent 0cad0edaaf
commit a27d4acd9f
12 changed files with 325 additions and 104 deletions

View File

@ -3,23 +3,20 @@ package org.bitcoins.chain.blockchain.sync
import org.bitcoins.chain.blockchain.ChainHandler
import org.bitcoins.core.api.chain.ChainApi
import org.bitcoins.crypto.DoubleSha256DigestBE
import org.bitcoins.testkit.chain.fixture.BitcoindChainHandlerViaRpc
import org.bitcoins.testkit.chain.{ChainDbUnitTest, SyncUtil}
import org.scalatest.FutureOutcome
import org.bitcoins.testkit.chain.SyncUtil
import org.bitcoins.testkit.chain.fixture.{
BitcoindBaseVersionChainHandlerViaRpc,
ChainWithBitcoindNewestCachedUnitTest
}
import scala.concurrent.Future
class ChainSyncTest extends ChainDbUnitTest {
override type FixtureParam = BitcoindChainHandlerViaRpc
override def withFixture(test: OneArgAsyncTest): FutureOutcome = {
withBitcoindChainHandlerViaRpc(test)
}
class ChainSyncTest extends ChainWithBitcoindNewestCachedUnitTest {
behavior of "ChainSync"
it must "sync our chain handler when it is not synced with bitcoind" in {
bitcoindWithChainHandler: BitcoindChainHandlerViaRpc =>
bitcoindWithChainHandler: BitcoindBaseVersionChainHandlerViaRpc =>
val bitcoind = bitcoindWithChainHandler.bitcoindRpc
val chainHandler = bitcoindWithChainHandler.chainHandler
//first we need to implement the 'getBestBlockHashFunc' and 'getBlockHeaderFunc' functions
@ -36,14 +33,17 @@ class ChainSyncTest extends ChainDbUnitTest {
getBestBlockHashFunc = getBestBlockHashFunc)
}
newChainHandlerF.flatMap { chainHandler =>
chainHandler.getBlockCount().map(count => assert(count == 1))
for {
chainHandler <- newChainHandlerF
count <- chainHandler.getBlockCount()
bitcoindCount <- bitcoind.getBlockCount
} yield {
assert(bitcoindCount == count)
}
}
it must "not fail when syncing a chain handler that is synced with it's external data source" in {
bitcoindWithChainHandler: BitcoindChainHandlerViaRpc =>
bitcoindWithChainHandler: BitcoindBaseVersionChainHandlerViaRpc =>
val bitcoind = bitcoindWithChainHandler.bitcoindRpc
val chainHandler = bitcoindWithChainHandler.chainHandler
//first we need to implement the 'getBestBlockHashFunc' and 'getBlockHeaderFunc' functions
@ -61,9 +61,18 @@ class ChainSyncTest extends ChainDbUnitTest {
getBlockHeaderFunc = getBlockHeaderFunc,
getBestBlockHashFunc = getBestBlockHashFunc)
newChainHandlerF.flatMap { chainHandler =>
chainHandler.getBlockCount().map(count => assert(count == 0))
}
val newChainHandler2F = for {
newChainHandler <- newChainHandlerF
//sync it again to make sure we don't fail
newChainHandler2 <- ChainSync.sync(
chainHandler = newChainHandler.asInstanceOf[ChainHandler],
getBlockHeaderFunc = getBlockHeaderFunc,
getBestBlockHashFunc = getBestBlockHashFunc)
bitcoinSCount <- newChainHandler2.getBlockCount()
bitcoindCount <- bitcoind.getBlockCount
} yield assert(bitcoinSCount == bitcoindCount)
newChainHandler2F
}
it must "be able to call sync() twice and not fail when nothing has happened" in {
@ -87,13 +96,15 @@ class ChainSyncTest extends ChainDbUnitTest {
}
val assertion1F = for {
hashes <- generate1F
_ <- generate1F
chainApiSync1 <- sync1F
count <- chainApiSync1.getBlockCount()
bestHash <- chainApiSync1.getBestBlockHash()
bitcoindBlockCount <- bitcoind.getBlockCount
bitcoindBestBlockHash <- bitcoind.getBestBlockHash
} yield {
assert(count == 1)
assert(bestHash == hashes.head)
assert(count == bitcoindBlockCount)
assert(bestHash == bitcoindBestBlockHash)
}
//let's call sync again and make sure nothing bad happens
@ -106,11 +117,13 @@ class ChainSyncTest extends ChainDbUnitTest {
getBlockHeaderFunc = getBlockHeaderFunc,
getBestBlockHashFunc = getBestBlockHashFunc)
count <- chainApiSync2.getBlockCount()
hashes <- generate1F
_ <- generate1F
bestHash <- chainApiSync2.getBestBlockHash()
bitcoindBlockCount <- bitcoind.getBlockCount
bitcoindBestBlockHash <- bitcoind.getBestBlockHash
} yield {
assert(count == 1)
assert(bestHash == hashes.head)
assert(count == bitcoindBlockCount)
assert(bestHash == bitcoindBestBlockHash)
}
sync2F

View File

@ -4,19 +4,15 @@ import org.bitcoins.chain.blockchain.ChainHandler
import org.bitcoins.core.api.chain.ChainApi
import org.bitcoins.core.gcs.FilterType
import org.bitcoins.core.protocol.blockchain.BlockHeader
import org.bitcoins.testkit.chain.fixture.BitcoindV19ChainHandler
import org.bitcoins.testkit.chain.{ChainDbUnitTest, SyncUtil}
import org.scalatest.FutureOutcome
import org.bitcoins.testkit.chain.SyncUtil
import org.bitcoins.testkit.chain.fixture.{
BitcoindV19ChainHandler,
ChainWithBitcoindV19CachedUnitTest
}
import scala.concurrent.Future
class FilterSyncTest extends ChainDbUnitTest {
override type FixtureParam = BitcoindV19ChainHandler
override def withFixture(test: OneArgAsyncTest): FutureOutcome = {
withBitcoindV19ChainHandlerViaRpc(test)
}
class FilterSyncTest extends ChainWithBitcoindV19CachedUnitTest {
behavior of "FilterSync"
@ -25,19 +21,25 @@ class FilterSyncTest extends ChainDbUnitTest {
val initFilterCountF = chainHandler.getFilterCount()
val initFilterHeaderCountF = chainHandler.getFilterHeaderCount()
val bitcoindFilterCountF = bitcoind.getFilterCount()
val initAssertionsF = for {
initFilterCount <- initFilterCountF
initFilterHeaderCount <- initFilterHeaderCountF
bitcoindFilterCount <- bitcoindFilterCountF
} yield {
assert(initFilterCount == 0)
assert(initFilterHeaderCount == 0)
assert(initFilterCount == bitcoindFilterCount)
assert(initFilterHeaderCount == bitcoindFilterCount)
}
val generated1BlockF = for {
_ <- initAssertionsF
addr <- bitcoind.getNewAddress
hashes <- bitcoind.generateToAddress(1, addr)
} yield hashes
} yield {
hashes
}
val syncedF = generated1BlockF.flatMap { _ =>
syncHelper(fixture)
@ -46,9 +48,10 @@ class FilterSyncTest extends ChainDbUnitTest {
for {
syncedChainApi <- syncedF
filterHeaderCount <- syncedChainApi.getFilterHeaderCount()
_ = assert(filterHeaderCount == 1)
bitcoindFilterCount <- bitcoind.getFilterCount()
_ = assert(filterHeaderCount == bitcoindFilterCount)
filterCount <- syncedChainApi.getFilterCount()
} yield assert(filterCount == 1)
} yield assert(filterCount == bitcoindFilterCount)
}
it must "sync a bunch of filter headers from an external data source" in {
@ -67,10 +70,11 @@ class FilterSyncTest extends ChainDbUnitTest {
for {
syncedChainApi <- syncedF
bitcoindFilterCount <- bitcoind.getFilterCount()
filterHeaderCount <- syncedChainApi.getFilterHeaderCount()
_ = assert(filterHeaderCount == numBlocks)
_ = assert(filterHeaderCount == bitcoindFilterCount)
filterCount <- syncedChainApi.getFilterCount()
} yield assert(filterCount == numBlocks)
} yield assert(filterCount == bitcoindFilterCount)
}
it must "be able to call filterSync() and not fail when nothing has happened" in {
@ -93,10 +97,11 @@ class FilterSyncTest extends ChainDbUnitTest {
for {
syncedChainApi <- sync2F
bitcoindFilterCount <- bitcoind.getFilterCount()
filterHeaderCount <- syncedChainApi.getFilterHeaderCount()
_ = assert(filterHeaderCount == 1)
_ = assert(filterHeaderCount == bitcoindFilterCount)
filterCount <- syncedChainApi.getFilterCount()
} yield assert(filterCount == 1)
} yield assert(filterCount == bitcoindFilterCount)
}
private def syncHelper(
@ -111,10 +116,10 @@ class FilterSyncTest extends ChainDbUnitTest {
SyncUtil.getFilterFunc(bitcoind, filterType)
//first sync the chain
val syncedHeadersF = ChainSync.sync(chainHandler = chainHandler,
getBlockHeaderFunc = getBlockHeaderFunc,
getBestBlockHashFunc =
getBestBlockHashFunc)
val syncedHeadersF: Future[ChainApi] = ChainSync.sync(
chainHandler = chainHandler,
getBlockHeaderFunc = getBlockHeaderFunc,
getBestBlockHashFunc = getBestBlockHashFunc)
//now sync filters
syncedHeadersF.flatMap { syncedChainHandler =>

View File

@ -68,7 +68,6 @@ abstract class ChainSync extends ChainVerificationLogger {
getBlockHeaderFunc: DoubleSha256DigestBE => Future[BlockHeader])(implicit
ec: ExecutionContext): Future[ChainApi] = {
require(tips.nonEmpty, s"Cannot sync without the genesis block")
//we need to walk backwards on the chain until we get to one of our tips
val tipsBH = tips.map(_.blockHeader)

View File

@ -34,7 +34,6 @@ abstract class FilterSync extends ChainVerificationLogger {
batchSize: Int = 25)(implicit
ec: ExecutionContext,
chainAppConfig: ChainAppConfig): Future[ChainApi] = {
val ourBestFilterHeaderOptF = chainApi.getBestFilterHeader()
val ourBestBlockHeaderF = chainApi.getBestBlockHeader()
for {
@ -96,7 +95,17 @@ abstract class FilterSync extends ChainVerificationLogger {
missing <- chainApi.getHeadersBetween(from = bestFilterBlockHeader.get,
to = ourBestHeader)
} yield {
missing
//getHeaderBetween is inclusive with 'from' parameter,
//we only want the inclusive behavior when we are fetching
//from the genesis block hash, so we can get the genesis filter
//else we need the _next_ header after our bestFilterBlockHeader
if (
bestFilterBlockHeader.get.hashBE == chainAppConfig.chain.genesisHashBE
) {
missing
} else {
missing.tail
}
}
//because filters can be really large, we don't want to process too many

View File

@ -5,7 +5,8 @@ import org.bitcoins.crypto.DoubleSha256DigestBE
/** Represents a [[GolombFilter]] with it's [[org.bitcoins.core.gcs.FilterHeader]] associated with it
* This is needed because bitcoin core's 'getblockfilter' rpc returns things in this structure
* @see https://developer.bitcoin.org/reference/rpc/getblockfilter.html#argument-2-filtertype
*/
case class FilterWithHeaderHash(
filter: GolombFilter,
headerHash: DoubleSha256DigestBE)
filterHeaderHash: DoubleSha256DigestBE)

View File

@ -64,7 +64,7 @@ implicit val chainAppConfig = BitcoinSTestAppConfig.getNeutrinoTestConfig().chai
val bitcoindWithChainApiF: Future[BitcoindV19ChainHandler] = {
ChainUnitTest.createBitcoindV19ChainHandler()
}
val bitcoindF = bitcoindWithChainApiF.map(_.bitcoind)
val bitcoindF = bitcoindWithChainApiF.map(_.bitcoindRpc)
val chainApiF = bitcoindWithChainApiF.map(_.chainHandler)
val filterType = FilterType.Basic

View File

@ -173,6 +173,7 @@ akka {
event-stream=off
}
# https://doc.akka.io/docs/akka/current/dispatchers.html#classic-dispatchers
default-dispatcher {
# The goal here is to reduce the number of threads spun up for test suites.
# Since every test suite currently
@ -194,20 +195,20 @@ akka {
executor = "thread-pool-executor"
throughput = 1
thread-pool-executor {
fixed-pool-size = 2
fixed-pool-size = 1
}
}
internal-dispatcher {
# minimum of one thread for tests
parallelism-min = 1
# maximum of 2 threads for tests
parallelism-max = 2
# maximum of 1 threads for tests
parallelism-max = 1
type = "Dispatcher"
executor = "thread-pool-executor"
throughput = 1
thread-pool-executor {
fixed-pool-size = 2
fixed-pool-size = 1
}
}
}

View File

@ -1,11 +1,10 @@
package org.bitcoins.testkit.chain
import java.net.InetSocketAddress
import akka.actor.ActorSystem
import com.typesafe.config.ConfigFactory
import org.bitcoins.chain.ChainVerificationLogger
import org.bitcoins.chain.blockchain.{ChainHandler, ChainHandlerCached}
import org.bitcoins.chain.blockchain.sync.ChainSync
import org.bitcoins.chain.blockchain.{ChainHandler, ChainHandlerCached}
import org.bitcoins.chain.config.ChainAppConfig
import org.bitcoins.chain.models._
import org.bitcoins.chain.pow.Pow
@ -33,9 +32,10 @@ import org.bitcoins.zmq.ZMQSubscriber
import org.scalatest._
import play.api.libs.json.{JsError, JsSuccess, Json}
import java.net.InetSocketAddress
import scala.annotation.tailrec
import scala.concurrent.{ExecutionContext, Future}
import scala.concurrent.duration.DurationInt
import scala.concurrent.{ExecutionContext, Future}
trait ChainUnitTest
extends BitcoinSFixture
@ -271,7 +271,7 @@ trait ChainUnitTest
bitcoindChainHandler: BitcoindChainHandlerViaZmq): Future[Unit] = {
//piggy back off of rpc destructor
val rpc = chain.fixture.BitcoindChainHandlerViaRpc(
val rpc = chain.fixture.BitcoindBaseVersionChainHandlerViaRpc(
bitcoindChainHandler.bitcoindRpc,
bitcoindChainHandler.chainHandler)
@ -300,7 +300,7 @@ trait ChainUnitTest
def withBitcoindChainHandlerViaRpc(test: OneArgAsyncTest)(implicit
system: ActorSystem): FutureOutcome = {
val builder: () => Future[BitcoindChainHandlerViaRpc] = { () =>
val builder: () => Future[BitcoindBaseVersionChainHandlerViaRpc] = { () =>
BitcoinSFixture
.createBitcoind()
.flatMap(ChainUnitTest.createChainApiWithBitcoindRpc)
@ -310,15 +310,6 @@ trait ChainUnitTest
test)
}
def withBitcoindV19ChainHandlerViaRpc(test: OneArgAsyncTest)(implicit
system: ActorSystem): FutureOutcome = {
val builder: () => Future[BitcoindV19ChainHandler] = { () =>
ChainUnitTest.createBitcoindV19ChainHandler()
}
makeDependentFixture(builder, ChainUnitTest.destroyBitcoindV19ChainApi)(
test)
}
final def processHeaders(
processorF: Future[ChainApi],
headers: Vector[BlockHeader],
@ -569,19 +560,20 @@ object ChainUnitTest extends ChainVerificationLogger {
def createChainApiWithBitcoindRpc(bitcoind: BitcoindRpcClient)(implicit
ec: ExecutionContext,
chainAppConfig: ChainAppConfig): Future[BitcoindChainHandlerViaRpc] = {
chainAppConfig: ChainAppConfig): Future[
BitcoindBaseVersionChainHandlerViaRpc] = {
val handlerWithGenesisHeaderF =
ChainUnitTest.setupHeaderTableWithGenesisHeader()
val chainHandlerF = handlerWithGenesisHeaderF.map(_._1)
chainHandlerF.map { handler =>
chain.fixture.BitcoindChainHandlerViaRpc(bitcoind, handler)
chain.fixture.BitcoindBaseVersionChainHandlerViaRpc(bitcoind, handler)
}
}
def destroyBitcoindChainApiViaRpc(
bitcoindChainHandler: BitcoindChainHandlerViaRpc)(implicit
bitcoindChainHandler: BitcoindBaseVersionChainHandlerViaRpc)(implicit
system: ActorSystem,
chainAppConfig: ChainAppConfig): Future[Unit] = {
import system.dispatcher
@ -591,30 +583,6 @@ object ChainUnitTest extends ChainVerificationLogger {
stopBitcoindF.flatMap(_ => dropTableF)
}
def createBitcoindV19ChainHandler()(implicit
system: ActorSystem,
chainAppConfig: ChainAppConfig): Future[BitcoindV19ChainHandler] = {
import system.dispatcher
val bitcoindV = BitcoindVersion.V19
BitcoinSFixture
.createBitcoind(Some(bitcoindV))
.flatMap(createChainApiWithBitcoindRpc)
.map { b: BitcoindChainHandlerViaRpc =>
BitcoindV19ChainHandler(
b.bitcoindRpc.asInstanceOf[BitcoindV19RpcClient],
b.chainHandler)
}
}
def destroyBitcoindV19ChainApi(
bitcoindV19ChainHandler: BitcoindV19ChainHandler)(implicit
system: ActorSystem,
chainAppConfig: ChainAppConfig): Future[Unit] = {
val b = BitcoindChainHandlerViaRpc(bitcoindV19ChainHandler.bitcoind,
bitcoindV19ChainHandler.chainHandler)
destroyBitcoindChainApiViaRpc(b)
}
def destroyBitcoind(bitcoind: BitcoindRpcClient)(implicit
system: ActorSystem): Future[Unit] = {
BitcoindRpcTestUtil.stopServer(bitcoind)
@ -685,4 +653,66 @@ object ChainUnitTest extends ChainVerificationLogger {
ChainSync.sync(chainHandler, getBlockHeaderFunc, getBestBlockHashFunc)
}
def createBitcoindV19ChainHandler()(implicit
system: ActorSystem,
chainAppConfig: ChainAppConfig): Future[BitcoindV19ChainHandler] = {
import system.dispatcher
val bitcoindV = BitcoindVersion.V19
val bitcoindF = BitcoinSFixture
.createBitcoind(Some(bitcoindV))
.map(_.asInstanceOf[BitcoindV19RpcClient])
bitcoindF.flatMap(b => createBitcoindV19ChainHandler(b))
}
def createBitcoindV19ChainHandler(
bitcoindV19RpcClient: BitcoindV19RpcClient)(implicit
ec: ExecutionContext,
chainAppConfig: ChainAppConfig): Future[BitcoindV19ChainHandler] = {
val chainApiWithBitcoindF = createChainApiWithBitcoindV19Rpc(
bitcoindV19RpcClient)
//now sync the chain api to the bitcoind node
val syncedBitcoindWithChainHandlerF = for {
chainApiWithBitcoind <- chainApiWithBitcoindF
bitcoindWithChainHandler <- SyncUtil.syncBitcoindV19WithChainHandler(
chainApiWithBitcoind)
} yield bitcoindWithChainHandler
syncedBitcoindWithChainHandlerF
}
private def createChainApiWithBitcoindV19Rpc(
bitcoind: BitcoindV19RpcClient)(implicit
ec: ExecutionContext,
chainAppConfig: ChainAppConfig): Future[BitcoindV19ChainHandler] = {
val handlerWithGenesisHeaderF =
ChainUnitTest.setupHeaderTableWithGenesisHeader()
val chainHandlerF = handlerWithGenesisHeaderF.map(_._1)
chainHandlerF.map { handler =>
BitcoindV19ChainHandler(bitcoind, handler)
}
}
def destroyBitcoindV19ChainApi(
bitcoindV19ChainHandler: BitcoindV19ChainHandler)(implicit
system: ActorSystem,
chainAppConfig: ChainAppConfig): Future[Unit] = {
val b = BitcoindBaseVersionChainHandlerViaRpc(
bitcoindV19ChainHandler.bitcoindRpc,
bitcoindV19ChainHandler.chainHandler)
destroyBitcoindChainApiViaRpc(b)
}
/** Destroys the chain api, but leaves the bitcoind instance running
* so we can cache it
*/
def destroyChainApi()(implicit
system: ActorSystem,
chainAppConfig: ChainAppConfig): Future[Unit] = {
ChainUnitTest.destroyAllTables()(chainAppConfig, system.dispatcher)
}
}

View File

@ -1,6 +1,13 @@
package org.bitcoins.testkit.chain
import org.bitcoins.chain.blockchain.sync.FilterWithHeaderHash
import grizzled.slf4j.Logging
import org.bitcoins.chain.blockchain.ChainHandler
import org.bitcoins.chain.blockchain.sync.{
ChainSync,
FilterSync,
FilterWithHeaderHash
}
import org.bitcoins.chain.config.ChainAppConfig
import org.bitcoins.commons.jsonmodels.bitcoind.GetBlockFilterResult
import org.bitcoins.core.api.node
import org.bitcoins.core.api.node.{NodeApi, NodeChainQueryApi}
@ -11,9 +18,13 @@ import org.bitcoins.core.util.FutureUtil
import org.bitcoins.crypto.{DoubleSha256Digest, DoubleSha256DigestBE}
import org.bitcoins.rpc.client.common.BitcoindRpcClient
import org.bitcoins.rpc.client.v19.BitcoindV19RpcClient
import org.bitcoins.testkit.chain.fixture.{
BitcoindBaseVersionChainHandlerViaRpc,
BitcoindChainHandlerViaRpc,
BitcoindV19ChainHandler
}
import org.bitcoins.wallet.Wallet
import org.bitcoins.wallet.sync.WalletSync
import grizzled.slf4j.Logging
import scala.concurrent.{ExecutionContext, Future}
@ -176,6 +187,57 @@ abstract class SyncUtil extends Logging {
getBlockFunc = SyncUtil.getBlockFunc(bitcoind)
)
}
/** Syncs the given chain handler to the given bitcoind node.
* This does NOT sync this like block filters, as we cannot
* determine if the bitcoind version passed to us has support for block filters
*/
def syncBitcoindWithChainHandler(
bitcoindWithChainHandler: BitcoindChainHandlerViaRpc)(implicit
ec: ExecutionContext): Future[BitcoindBaseVersionChainHandlerViaRpc] = {
val getBestBlockHash = getBestBlockHashFunc(
bitcoindWithChainHandler.bitcoindRpc)
val getBlockHeader = getBlockHeaderFunc(
bitcoindWithChainHandler.bitcoindRpc)
val chainApiF = ChainSync.sync(bitcoindWithChainHandler.chainHandler,
getBlockHeader,
getBestBlockHash)
for {
chainApi <- chainApiF
} yield BitcoindBaseVersionChainHandlerViaRpc(
bitcoindRpc = bitcoindWithChainHandler.bitcoindRpc,
chainHandler = chainApi.asInstanceOf[ChainHandler])
}
/** Syncs the given chain handler to the given bitcoind node. This also syncs block filters
* since we know a bitcoind v19 node has block filter capability
*/
def syncBitcoindV19WithChainHandler(
bitcoindWithChainHandler: BitcoindV19ChainHandler)(implicit
ec: ExecutionContext,
chainAppConfig: ChainAppConfig): Future[BitcoindV19ChainHandler] = {
val bitcoindV19 = bitcoindWithChainHandler.bitcoindRpc
val chainApiF = syncBitcoindWithChainHandler(bitcoindWithChainHandler)
.map(_.chainHandler)
val getFilter: BlockHeader => Future[FilterWithHeaderHash] = {
getFilterFunc(bitcoindV19, FilterType.Basic)
}
for {
chainApi <- chainApiF
filterSyncChainApi <- FilterSync.syncFilters(chainApi, getFilter)
bestBlockHash <- bitcoindV19.getBestBlockHash
ourBestFilter <- chainApi.getBestFilterHeader()
_ = require(
bestBlockHash == ourBestFilter.get.blockHashBE,
s"We did not sync filter's in our fixture bitcoindBestBlockHash=$bestBlockHash our best filter's blockHash=${ourBestFilter.get.blockHashBE}"
)
} yield BitcoindV19ChainHandler(
bitcoindRpc = bitcoindWithChainHandler.bitcoindRpc,
chainHandler = filterSyncChainApi.asInstanceOf[ChainHandler])
}
}
object SyncUtil extends SyncUtil

View File

@ -2,8 +2,23 @@ package org.bitcoins.testkit.chain.fixture
import org.bitcoins.chain.blockchain.ChainHandler
import org.bitcoins.rpc.client.common.BitcoindRpcClient
import org.bitcoins.rpc.client.v19.BitcoindV19RpcClient
/** Represents a bitcoind instance paired with a chain handler via rpc */
case class BitcoindChainHandlerViaRpc(
sealed trait BitcoindChainHandlerViaRpc {
def bitcoindRpc: BitcoindRpcClient
def chainHandler: ChainHandler
}
/** Represents a bitcoind instance paired with a chain handler via rpc
* This is useful for when the bitcoind version doesn't matter, you
* just need a generic [[BitcoindRpcClient]]
*/
case class BitcoindBaseVersionChainHandlerViaRpc(
bitcoindRpc: BitcoindRpcClient,
chainHandler: ChainHandler)
extends BitcoindChainHandlerViaRpc
case class BitcoindV19ChainHandler(
override val bitcoindRpc: BitcoindV19RpcClient,
chainHandler: ChainHandler)
extends BitcoindChainHandlerViaRpc

View File

@ -0,0 +1,89 @@
package org.bitcoins.testkit.chain.fixture
import org.bitcoins.rpc.client.common.BitcoindRpcClient
import org.bitcoins.rpc.client.v19.BitcoindV19RpcClient
import org.bitcoins.testkit.chain.{ChainDbUnitTest, ChainUnitTest}
import org.bitcoins.testkit.rpc.{
CachedBitcoind,
CachedBitcoindNewest,
CachedBitcoindV19
}
import org.scalatest.{FutureOutcome, Outcome}
import scala.concurrent.Future
/** Chain unit test that requires a cached bitcoind type to be injected */
trait ChainWithBitcoindUnitTest extends ChainDbUnitTest {
_: CachedBitcoind[_] =>
}
trait ChainWithBitcoindNewestCachedUnitTest
extends ChainWithBitcoindUnitTest
with CachedBitcoindNewest {
override type FixtureParam = BitcoindBaseVersionChainHandlerViaRpc
override def withFixture(test: OneArgAsyncTest): FutureOutcome = {
val f: Future[Outcome] = for {
bitcoind <- cachedBitcoindWithFundsF
futOutcome = withBitcoindNewestChainHandlerViaRpc(test, bitcoind)
fut <- futOutcome.toFuture
} yield fut
new FutureOutcome(f)
}
def withBitcoindNewestChainHandlerViaRpc(
test: OneArgAsyncTest,
bitcoindRpcClient: BitcoindRpcClient): FutureOutcome = {
val builder: () => Future[BitcoindBaseVersionChainHandlerViaRpc] = { () =>
ChainUnitTest.createChainApiWithBitcoindRpc(bitcoindRpcClient)
}
val destroy: BitcoindBaseVersionChainHandlerViaRpc => Future[Unit] = {
case _: BitcoindBaseVersionChainHandlerViaRpc =>
ChainUnitTest.destroyChainApi()
}
makeDependentFixture(builder, destroy)(test)
}
override def afterAll(): Unit = {
super[CachedBitcoindNewest].afterAll()
super[ChainWithBitcoindUnitTest].afterAll()
}
}
/** Chain Unit test suite that has a cached bitcoind v19 instance */
trait ChainWithBitcoindV19CachedUnitTest
extends ChainWithBitcoindUnitTest
with CachedBitcoindV19 {
override type FixtureParam = BitcoindV19ChainHandler
override def withFixture(test: OneArgAsyncTest): FutureOutcome = {
val f: Future[Outcome] = for {
bitcoind <- cachedBitcoindWithFundsF
futOutcome = withBitcoindV19ChainHandlerViaRpc(test, bitcoind)
fut <- futOutcome.toFuture
} yield fut
new FutureOutcome(f)
}
def withBitcoindV19ChainHandlerViaRpc(
test: OneArgAsyncTest,
bitcoindV19RpcClient: BitcoindV19RpcClient): FutureOutcome = {
val builder: () => Future[BitcoindV19ChainHandler] = { () =>
ChainUnitTest.createBitcoindV19ChainHandler(bitcoindV19RpcClient)
}
val destroy: BitcoindV19ChainHandler => Future[Unit] = {
case _: BitcoindV19ChainHandler =>
ChainUnitTest.destroyChainApi()
}
makeDependentFixture(builder, destroy)(test)
}
override def afterAll(): Unit = {
super[CachedBitcoindV19].afterAll()
super[ChainWithBitcoindUnitTest].afterAll()
}
}

View File

@ -5,7 +5,6 @@ import org.bitcoins.core.currency._
import org.bitcoins.core.gcs.FilterType
import org.bitcoins.core.util.FutureUtil
import org.bitcoins.core.wallet.utxo.TxoState
import org.bitcoins.testkit.rpc.CachedBitcoindV19
import org.bitcoins.testkit.wallet.{
BitcoinSWalletTestCachedBitcoinV19,
WalletWithBitcoindV19
@ -14,9 +13,7 @@ import org.scalatest.{FutureOutcome, Outcome}
import scala.concurrent.Future
class ProcessBlockTest
extends BitcoinSWalletTestCachedBitcoinV19
with CachedBitcoindV19 {
class ProcessBlockTest extends BitcoinSWalletTestCachedBitcoinV19 {
override type FixtureParam = WalletWithBitcoindV19