mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-01-18 21:34:39 +01:00
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:
parent
0cad0edaaf
commit
a27d4acd9f
@ -3,23 +3,20 @@ package org.bitcoins.chain.blockchain.sync
|
|||||||
import org.bitcoins.chain.blockchain.ChainHandler
|
import org.bitcoins.chain.blockchain.ChainHandler
|
||||||
import org.bitcoins.core.api.chain.ChainApi
|
import org.bitcoins.core.api.chain.ChainApi
|
||||||
import org.bitcoins.crypto.DoubleSha256DigestBE
|
import org.bitcoins.crypto.DoubleSha256DigestBE
|
||||||
import org.bitcoins.testkit.chain.fixture.BitcoindChainHandlerViaRpc
|
import org.bitcoins.testkit.chain.SyncUtil
|
||||||
import org.bitcoins.testkit.chain.{ChainDbUnitTest, SyncUtil}
|
import org.bitcoins.testkit.chain.fixture.{
|
||||||
import org.scalatest.FutureOutcome
|
BitcoindBaseVersionChainHandlerViaRpc,
|
||||||
|
ChainWithBitcoindNewestCachedUnitTest
|
||||||
|
}
|
||||||
|
|
||||||
import scala.concurrent.Future
|
import scala.concurrent.Future
|
||||||
|
|
||||||
class ChainSyncTest extends ChainDbUnitTest {
|
class ChainSyncTest extends ChainWithBitcoindNewestCachedUnitTest {
|
||||||
override type FixtureParam = BitcoindChainHandlerViaRpc
|
|
||||||
|
|
||||||
override def withFixture(test: OneArgAsyncTest): FutureOutcome = {
|
|
||||||
withBitcoindChainHandlerViaRpc(test)
|
|
||||||
}
|
|
||||||
|
|
||||||
behavior of "ChainSync"
|
behavior of "ChainSync"
|
||||||
|
|
||||||
it must "sync our chain handler when it is not synced with bitcoind" in {
|
it must "sync our chain handler when it is not synced with bitcoind" in {
|
||||||
bitcoindWithChainHandler: BitcoindChainHandlerViaRpc =>
|
bitcoindWithChainHandler: BitcoindBaseVersionChainHandlerViaRpc =>
|
||||||
val bitcoind = bitcoindWithChainHandler.bitcoindRpc
|
val bitcoind = bitcoindWithChainHandler.bitcoindRpc
|
||||||
val chainHandler = bitcoindWithChainHandler.chainHandler
|
val chainHandler = bitcoindWithChainHandler.chainHandler
|
||||||
//first we need to implement the 'getBestBlockHashFunc' and 'getBlockHeaderFunc' functions
|
//first we need to implement the 'getBestBlockHashFunc' and 'getBlockHeaderFunc' functions
|
||||||
@ -36,14 +33,17 @@ class ChainSyncTest extends ChainDbUnitTest {
|
|||||||
getBestBlockHashFunc = getBestBlockHashFunc)
|
getBestBlockHashFunc = getBestBlockHashFunc)
|
||||||
}
|
}
|
||||||
|
|
||||||
newChainHandlerF.flatMap { chainHandler =>
|
for {
|
||||||
chainHandler.getBlockCount().map(count => assert(count == 1))
|
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 {
|
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 bitcoind = bitcoindWithChainHandler.bitcoindRpc
|
||||||
val chainHandler = bitcoindWithChainHandler.chainHandler
|
val chainHandler = bitcoindWithChainHandler.chainHandler
|
||||||
//first we need to implement the 'getBestBlockHashFunc' and 'getBlockHeaderFunc' functions
|
//first we need to implement the 'getBestBlockHashFunc' and 'getBlockHeaderFunc' functions
|
||||||
@ -61,9 +61,18 @@ class ChainSyncTest extends ChainDbUnitTest {
|
|||||||
getBlockHeaderFunc = getBlockHeaderFunc,
|
getBlockHeaderFunc = getBlockHeaderFunc,
|
||||||
getBestBlockHashFunc = getBestBlockHashFunc)
|
getBestBlockHashFunc = getBestBlockHashFunc)
|
||||||
|
|
||||||
newChainHandlerF.flatMap { chainHandler =>
|
val newChainHandler2F = for {
|
||||||
chainHandler.getBlockCount().map(count => assert(count == 0))
|
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 {
|
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 {
|
val assertion1F = for {
|
||||||
hashes <- generate1F
|
_ <- generate1F
|
||||||
chainApiSync1 <- sync1F
|
chainApiSync1 <- sync1F
|
||||||
count <- chainApiSync1.getBlockCount()
|
count <- chainApiSync1.getBlockCount()
|
||||||
bestHash <- chainApiSync1.getBestBlockHash()
|
bestHash <- chainApiSync1.getBestBlockHash()
|
||||||
|
bitcoindBlockCount <- bitcoind.getBlockCount
|
||||||
|
bitcoindBestBlockHash <- bitcoind.getBestBlockHash
|
||||||
} yield {
|
} yield {
|
||||||
assert(count == 1)
|
assert(count == bitcoindBlockCount)
|
||||||
assert(bestHash == hashes.head)
|
assert(bestHash == bitcoindBestBlockHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
//let's call sync again and make sure nothing bad happens
|
//let's call sync again and make sure nothing bad happens
|
||||||
@ -106,11 +117,13 @@ class ChainSyncTest extends ChainDbUnitTest {
|
|||||||
getBlockHeaderFunc = getBlockHeaderFunc,
|
getBlockHeaderFunc = getBlockHeaderFunc,
|
||||||
getBestBlockHashFunc = getBestBlockHashFunc)
|
getBestBlockHashFunc = getBestBlockHashFunc)
|
||||||
count <- chainApiSync2.getBlockCount()
|
count <- chainApiSync2.getBlockCount()
|
||||||
hashes <- generate1F
|
_ <- generate1F
|
||||||
bestHash <- chainApiSync2.getBestBlockHash()
|
bestHash <- chainApiSync2.getBestBlockHash()
|
||||||
|
bitcoindBlockCount <- bitcoind.getBlockCount
|
||||||
|
bitcoindBestBlockHash <- bitcoind.getBestBlockHash
|
||||||
} yield {
|
} yield {
|
||||||
assert(count == 1)
|
assert(count == bitcoindBlockCount)
|
||||||
assert(bestHash == hashes.head)
|
assert(bestHash == bitcoindBestBlockHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
sync2F
|
sync2F
|
||||||
|
@ -4,19 +4,15 @@ import org.bitcoins.chain.blockchain.ChainHandler
|
|||||||
import org.bitcoins.core.api.chain.ChainApi
|
import org.bitcoins.core.api.chain.ChainApi
|
||||||
import org.bitcoins.core.gcs.FilterType
|
import org.bitcoins.core.gcs.FilterType
|
||||||
import org.bitcoins.core.protocol.blockchain.BlockHeader
|
import org.bitcoins.core.protocol.blockchain.BlockHeader
|
||||||
import org.bitcoins.testkit.chain.fixture.BitcoindV19ChainHandler
|
import org.bitcoins.testkit.chain.SyncUtil
|
||||||
import org.bitcoins.testkit.chain.{ChainDbUnitTest, SyncUtil}
|
import org.bitcoins.testkit.chain.fixture.{
|
||||||
import org.scalatest.FutureOutcome
|
BitcoindV19ChainHandler,
|
||||||
|
ChainWithBitcoindV19CachedUnitTest
|
||||||
|
}
|
||||||
|
|
||||||
import scala.concurrent.Future
|
import scala.concurrent.Future
|
||||||
|
|
||||||
class FilterSyncTest extends ChainDbUnitTest {
|
class FilterSyncTest extends ChainWithBitcoindV19CachedUnitTest {
|
||||||
|
|
||||||
override type FixtureParam = BitcoindV19ChainHandler
|
|
||||||
|
|
||||||
override def withFixture(test: OneArgAsyncTest): FutureOutcome = {
|
|
||||||
withBitcoindV19ChainHandlerViaRpc(test)
|
|
||||||
}
|
|
||||||
|
|
||||||
behavior of "FilterSync"
|
behavior of "FilterSync"
|
||||||
|
|
||||||
@ -25,19 +21,25 @@ class FilterSyncTest extends ChainDbUnitTest {
|
|||||||
|
|
||||||
val initFilterCountF = chainHandler.getFilterCount()
|
val initFilterCountF = chainHandler.getFilterCount()
|
||||||
val initFilterHeaderCountF = chainHandler.getFilterHeaderCount()
|
val initFilterHeaderCountF = chainHandler.getFilterHeaderCount()
|
||||||
|
|
||||||
|
val bitcoindFilterCountF = bitcoind.getFilterCount()
|
||||||
|
|
||||||
val initAssertionsF = for {
|
val initAssertionsF = for {
|
||||||
initFilterCount <- initFilterCountF
|
initFilterCount <- initFilterCountF
|
||||||
initFilterHeaderCount <- initFilterHeaderCountF
|
initFilterHeaderCount <- initFilterHeaderCountF
|
||||||
|
bitcoindFilterCount <- bitcoindFilterCountF
|
||||||
} yield {
|
} yield {
|
||||||
assert(initFilterCount == 0)
|
assert(initFilterCount == bitcoindFilterCount)
|
||||||
assert(initFilterHeaderCount == 0)
|
assert(initFilterHeaderCount == bitcoindFilterCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
val generated1BlockF = for {
|
val generated1BlockF = for {
|
||||||
_ <- initAssertionsF
|
_ <- initAssertionsF
|
||||||
addr <- bitcoind.getNewAddress
|
addr <- bitcoind.getNewAddress
|
||||||
hashes <- bitcoind.generateToAddress(1, addr)
|
hashes <- bitcoind.generateToAddress(1, addr)
|
||||||
} yield hashes
|
} yield {
|
||||||
|
hashes
|
||||||
|
}
|
||||||
|
|
||||||
val syncedF = generated1BlockF.flatMap { _ =>
|
val syncedF = generated1BlockF.flatMap { _ =>
|
||||||
syncHelper(fixture)
|
syncHelper(fixture)
|
||||||
@ -46,9 +48,10 @@ class FilterSyncTest extends ChainDbUnitTest {
|
|||||||
for {
|
for {
|
||||||
syncedChainApi <- syncedF
|
syncedChainApi <- syncedF
|
||||||
filterHeaderCount <- syncedChainApi.getFilterHeaderCount()
|
filterHeaderCount <- syncedChainApi.getFilterHeaderCount()
|
||||||
_ = assert(filterHeaderCount == 1)
|
bitcoindFilterCount <- bitcoind.getFilterCount()
|
||||||
|
_ = assert(filterHeaderCount == bitcoindFilterCount)
|
||||||
filterCount <- syncedChainApi.getFilterCount()
|
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 {
|
it must "sync a bunch of filter headers from an external data source" in {
|
||||||
@ -67,10 +70,11 @@ class FilterSyncTest extends ChainDbUnitTest {
|
|||||||
|
|
||||||
for {
|
for {
|
||||||
syncedChainApi <- syncedF
|
syncedChainApi <- syncedF
|
||||||
|
bitcoindFilterCount <- bitcoind.getFilterCount()
|
||||||
filterHeaderCount <- syncedChainApi.getFilterHeaderCount()
|
filterHeaderCount <- syncedChainApi.getFilterHeaderCount()
|
||||||
_ = assert(filterHeaderCount == numBlocks)
|
_ = assert(filterHeaderCount == bitcoindFilterCount)
|
||||||
filterCount <- syncedChainApi.getFilterCount()
|
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 {
|
it must "be able to call filterSync() and not fail when nothing has happened" in {
|
||||||
@ -93,10 +97,11 @@ class FilterSyncTest extends ChainDbUnitTest {
|
|||||||
|
|
||||||
for {
|
for {
|
||||||
syncedChainApi <- sync2F
|
syncedChainApi <- sync2F
|
||||||
|
bitcoindFilterCount <- bitcoind.getFilterCount()
|
||||||
filterHeaderCount <- syncedChainApi.getFilterHeaderCount()
|
filterHeaderCount <- syncedChainApi.getFilterHeaderCount()
|
||||||
_ = assert(filterHeaderCount == 1)
|
_ = assert(filterHeaderCount == bitcoindFilterCount)
|
||||||
filterCount <- syncedChainApi.getFilterCount()
|
filterCount <- syncedChainApi.getFilterCount()
|
||||||
} yield assert(filterCount == 1)
|
} yield assert(filterCount == bitcoindFilterCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def syncHelper(
|
private def syncHelper(
|
||||||
@ -111,10 +116,10 @@ class FilterSyncTest extends ChainDbUnitTest {
|
|||||||
SyncUtil.getFilterFunc(bitcoind, filterType)
|
SyncUtil.getFilterFunc(bitcoind, filterType)
|
||||||
|
|
||||||
//first sync the chain
|
//first sync the chain
|
||||||
val syncedHeadersF = ChainSync.sync(chainHandler = chainHandler,
|
val syncedHeadersF: Future[ChainApi] = ChainSync.sync(
|
||||||
getBlockHeaderFunc = getBlockHeaderFunc,
|
chainHandler = chainHandler,
|
||||||
getBestBlockHashFunc =
|
getBlockHeaderFunc = getBlockHeaderFunc,
|
||||||
getBestBlockHashFunc)
|
getBestBlockHashFunc = getBestBlockHashFunc)
|
||||||
|
|
||||||
//now sync filters
|
//now sync filters
|
||||||
syncedHeadersF.flatMap { syncedChainHandler =>
|
syncedHeadersF.flatMap { syncedChainHandler =>
|
||||||
|
@ -68,7 +68,6 @@ abstract class ChainSync extends ChainVerificationLogger {
|
|||||||
getBlockHeaderFunc: DoubleSha256DigestBE => Future[BlockHeader])(implicit
|
getBlockHeaderFunc: DoubleSha256DigestBE => Future[BlockHeader])(implicit
|
||||||
ec: ExecutionContext): Future[ChainApi] = {
|
ec: ExecutionContext): Future[ChainApi] = {
|
||||||
require(tips.nonEmpty, s"Cannot sync without the genesis block")
|
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
|
//we need to walk backwards on the chain until we get to one of our tips
|
||||||
val tipsBH = tips.map(_.blockHeader)
|
val tipsBH = tips.map(_.blockHeader)
|
||||||
|
|
||||||
|
@ -34,7 +34,6 @@ abstract class FilterSync extends ChainVerificationLogger {
|
|||||||
batchSize: Int = 25)(implicit
|
batchSize: Int = 25)(implicit
|
||||||
ec: ExecutionContext,
|
ec: ExecutionContext,
|
||||||
chainAppConfig: ChainAppConfig): Future[ChainApi] = {
|
chainAppConfig: ChainAppConfig): Future[ChainApi] = {
|
||||||
|
|
||||||
val ourBestFilterHeaderOptF = chainApi.getBestFilterHeader()
|
val ourBestFilterHeaderOptF = chainApi.getBestFilterHeader()
|
||||||
val ourBestBlockHeaderF = chainApi.getBestBlockHeader()
|
val ourBestBlockHeaderF = chainApi.getBestBlockHeader()
|
||||||
for {
|
for {
|
||||||
@ -96,7 +95,17 @@ abstract class FilterSync extends ChainVerificationLogger {
|
|||||||
missing <- chainApi.getHeadersBetween(from = bestFilterBlockHeader.get,
|
missing <- chainApi.getHeadersBetween(from = bestFilterBlockHeader.get,
|
||||||
to = ourBestHeader)
|
to = ourBestHeader)
|
||||||
} yield {
|
} 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
|
//because filters can be really large, we don't want to process too many
|
||||||
|
@ -5,7 +5,8 @@ import org.bitcoins.crypto.DoubleSha256DigestBE
|
|||||||
|
|
||||||
/** Represents a [[GolombFilter]] with it's [[org.bitcoins.core.gcs.FilterHeader]] associated with it
|
/** 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
|
* 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(
|
case class FilterWithHeaderHash(
|
||||||
filter: GolombFilter,
|
filter: GolombFilter,
|
||||||
headerHash: DoubleSha256DigestBE)
|
filterHeaderHash: DoubleSha256DigestBE)
|
||||||
|
@ -64,7 +64,7 @@ implicit val chainAppConfig = BitcoinSTestAppConfig.getNeutrinoTestConfig().chai
|
|||||||
val bitcoindWithChainApiF: Future[BitcoindV19ChainHandler] = {
|
val bitcoindWithChainApiF: Future[BitcoindV19ChainHandler] = {
|
||||||
ChainUnitTest.createBitcoindV19ChainHandler()
|
ChainUnitTest.createBitcoindV19ChainHandler()
|
||||||
}
|
}
|
||||||
val bitcoindF = bitcoindWithChainApiF.map(_.bitcoind)
|
val bitcoindF = bitcoindWithChainApiF.map(_.bitcoindRpc)
|
||||||
val chainApiF = bitcoindWithChainApiF.map(_.chainHandler)
|
val chainApiF = bitcoindWithChainApiF.map(_.chainHandler)
|
||||||
|
|
||||||
val filterType = FilterType.Basic
|
val filterType = FilterType.Basic
|
||||||
|
@ -173,6 +173,7 @@ akka {
|
|||||||
|
|
||||||
event-stream=off
|
event-stream=off
|
||||||
}
|
}
|
||||||
|
# https://doc.akka.io/docs/akka/current/dispatchers.html#classic-dispatchers
|
||||||
default-dispatcher {
|
default-dispatcher {
|
||||||
# The goal here is to reduce the number of threads spun up for test suites.
|
# The goal here is to reduce the number of threads spun up for test suites.
|
||||||
# Since every test suite currently
|
# Since every test suite currently
|
||||||
@ -194,20 +195,20 @@ akka {
|
|||||||
executor = "thread-pool-executor"
|
executor = "thread-pool-executor"
|
||||||
throughput = 1
|
throughput = 1
|
||||||
thread-pool-executor {
|
thread-pool-executor {
|
||||||
fixed-pool-size = 2
|
fixed-pool-size = 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal-dispatcher {
|
internal-dispatcher {
|
||||||
# minimum of one thread for tests
|
# minimum of one thread for tests
|
||||||
parallelism-min = 1
|
parallelism-min = 1
|
||||||
|
|
||||||
# maximum of 2 threads for tests
|
# maximum of 1 threads for tests
|
||||||
parallelism-max = 2
|
parallelism-max = 1
|
||||||
type = "Dispatcher"
|
type = "Dispatcher"
|
||||||
executor = "thread-pool-executor"
|
executor = "thread-pool-executor"
|
||||||
throughput = 1
|
throughput = 1
|
||||||
thread-pool-executor {
|
thread-pool-executor {
|
||||||
fixed-pool-size = 2
|
fixed-pool-size = 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
package org.bitcoins.testkit.chain
|
package org.bitcoins.testkit.chain
|
||||||
|
|
||||||
import java.net.InetSocketAddress
|
|
||||||
import akka.actor.ActorSystem
|
import akka.actor.ActorSystem
|
||||||
import com.typesafe.config.ConfigFactory
|
import com.typesafe.config.ConfigFactory
|
||||||
import org.bitcoins.chain.ChainVerificationLogger
|
import org.bitcoins.chain.ChainVerificationLogger
|
||||||
import org.bitcoins.chain.blockchain.{ChainHandler, ChainHandlerCached}
|
|
||||||
import org.bitcoins.chain.blockchain.sync.ChainSync
|
import org.bitcoins.chain.blockchain.sync.ChainSync
|
||||||
|
import org.bitcoins.chain.blockchain.{ChainHandler, ChainHandlerCached}
|
||||||
import org.bitcoins.chain.config.ChainAppConfig
|
import org.bitcoins.chain.config.ChainAppConfig
|
||||||
import org.bitcoins.chain.models._
|
import org.bitcoins.chain.models._
|
||||||
import org.bitcoins.chain.pow.Pow
|
import org.bitcoins.chain.pow.Pow
|
||||||
@ -33,9 +32,10 @@ import org.bitcoins.zmq.ZMQSubscriber
|
|||||||
import org.scalatest._
|
import org.scalatest._
|
||||||
import play.api.libs.json.{JsError, JsSuccess, Json}
|
import play.api.libs.json.{JsError, JsSuccess, Json}
|
||||||
|
|
||||||
|
import java.net.InetSocketAddress
|
||||||
import scala.annotation.tailrec
|
import scala.annotation.tailrec
|
||||||
import scala.concurrent.{ExecutionContext, Future}
|
|
||||||
import scala.concurrent.duration.DurationInt
|
import scala.concurrent.duration.DurationInt
|
||||||
|
import scala.concurrent.{ExecutionContext, Future}
|
||||||
|
|
||||||
trait ChainUnitTest
|
trait ChainUnitTest
|
||||||
extends BitcoinSFixture
|
extends BitcoinSFixture
|
||||||
@ -271,7 +271,7 @@ trait ChainUnitTest
|
|||||||
bitcoindChainHandler: BitcoindChainHandlerViaZmq): Future[Unit] = {
|
bitcoindChainHandler: BitcoindChainHandlerViaZmq): Future[Unit] = {
|
||||||
|
|
||||||
//piggy back off of rpc destructor
|
//piggy back off of rpc destructor
|
||||||
val rpc = chain.fixture.BitcoindChainHandlerViaRpc(
|
val rpc = chain.fixture.BitcoindBaseVersionChainHandlerViaRpc(
|
||||||
bitcoindChainHandler.bitcoindRpc,
|
bitcoindChainHandler.bitcoindRpc,
|
||||||
bitcoindChainHandler.chainHandler)
|
bitcoindChainHandler.chainHandler)
|
||||||
|
|
||||||
@ -300,7 +300,7 @@ trait ChainUnitTest
|
|||||||
|
|
||||||
def withBitcoindChainHandlerViaRpc(test: OneArgAsyncTest)(implicit
|
def withBitcoindChainHandlerViaRpc(test: OneArgAsyncTest)(implicit
|
||||||
system: ActorSystem): FutureOutcome = {
|
system: ActorSystem): FutureOutcome = {
|
||||||
val builder: () => Future[BitcoindChainHandlerViaRpc] = { () =>
|
val builder: () => Future[BitcoindBaseVersionChainHandlerViaRpc] = { () =>
|
||||||
BitcoinSFixture
|
BitcoinSFixture
|
||||||
.createBitcoind()
|
.createBitcoind()
|
||||||
.flatMap(ChainUnitTest.createChainApiWithBitcoindRpc)
|
.flatMap(ChainUnitTest.createChainApiWithBitcoindRpc)
|
||||||
@ -310,15 +310,6 @@ trait ChainUnitTest
|
|||||||
test)
|
test)
|
||||||
}
|
}
|
||||||
|
|
||||||
def withBitcoindV19ChainHandlerViaRpc(test: OneArgAsyncTest)(implicit
|
|
||||||
system: ActorSystem): FutureOutcome = {
|
|
||||||
val builder: () => Future[BitcoindV19ChainHandler] = { () =>
|
|
||||||
ChainUnitTest.createBitcoindV19ChainHandler()
|
|
||||||
}
|
|
||||||
makeDependentFixture(builder, ChainUnitTest.destroyBitcoindV19ChainApi)(
|
|
||||||
test)
|
|
||||||
}
|
|
||||||
|
|
||||||
final def processHeaders(
|
final def processHeaders(
|
||||||
processorF: Future[ChainApi],
|
processorF: Future[ChainApi],
|
||||||
headers: Vector[BlockHeader],
|
headers: Vector[BlockHeader],
|
||||||
@ -569,19 +560,20 @@ object ChainUnitTest extends ChainVerificationLogger {
|
|||||||
|
|
||||||
def createChainApiWithBitcoindRpc(bitcoind: BitcoindRpcClient)(implicit
|
def createChainApiWithBitcoindRpc(bitcoind: BitcoindRpcClient)(implicit
|
||||||
ec: ExecutionContext,
|
ec: ExecutionContext,
|
||||||
chainAppConfig: ChainAppConfig): Future[BitcoindChainHandlerViaRpc] = {
|
chainAppConfig: ChainAppConfig): Future[
|
||||||
|
BitcoindBaseVersionChainHandlerViaRpc] = {
|
||||||
val handlerWithGenesisHeaderF =
|
val handlerWithGenesisHeaderF =
|
||||||
ChainUnitTest.setupHeaderTableWithGenesisHeader()
|
ChainUnitTest.setupHeaderTableWithGenesisHeader()
|
||||||
|
|
||||||
val chainHandlerF = handlerWithGenesisHeaderF.map(_._1)
|
val chainHandlerF = handlerWithGenesisHeaderF.map(_._1)
|
||||||
|
|
||||||
chainHandlerF.map { handler =>
|
chainHandlerF.map { handler =>
|
||||||
chain.fixture.BitcoindChainHandlerViaRpc(bitcoind, handler)
|
chain.fixture.BitcoindBaseVersionChainHandlerViaRpc(bitcoind, handler)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def destroyBitcoindChainApiViaRpc(
|
def destroyBitcoindChainApiViaRpc(
|
||||||
bitcoindChainHandler: BitcoindChainHandlerViaRpc)(implicit
|
bitcoindChainHandler: BitcoindBaseVersionChainHandlerViaRpc)(implicit
|
||||||
system: ActorSystem,
|
system: ActorSystem,
|
||||||
chainAppConfig: ChainAppConfig): Future[Unit] = {
|
chainAppConfig: ChainAppConfig): Future[Unit] = {
|
||||||
import system.dispatcher
|
import system.dispatcher
|
||||||
@ -591,30 +583,6 @@ object ChainUnitTest extends ChainVerificationLogger {
|
|||||||
stopBitcoindF.flatMap(_ => dropTableF)
|
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
|
def destroyBitcoind(bitcoind: BitcoindRpcClient)(implicit
|
||||||
system: ActorSystem): Future[Unit] = {
|
system: ActorSystem): Future[Unit] = {
|
||||||
BitcoindRpcTestUtil.stopServer(bitcoind)
|
BitcoindRpcTestUtil.stopServer(bitcoind)
|
||||||
@ -685,4 +653,66 @@ object ChainUnitTest extends ChainVerificationLogger {
|
|||||||
|
|
||||||
ChainSync.sync(chainHandler, getBlockHeaderFunc, getBestBlockHashFunc)
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,13 @@
|
|||||||
package org.bitcoins.testkit.chain
|
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.commons.jsonmodels.bitcoind.GetBlockFilterResult
|
||||||
import org.bitcoins.core.api.node
|
import org.bitcoins.core.api.node
|
||||||
import org.bitcoins.core.api.node.{NodeApi, NodeChainQueryApi}
|
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.crypto.{DoubleSha256Digest, DoubleSha256DigestBE}
|
||||||
import org.bitcoins.rpc.client.common.BitcoindRpcClient
|
import org.bitcoins.rpc.client.common.BitcoindRpcClient
|
||||||
import org.bitcoins.rpc.client.v19.BitcoindV19RpcClient
|
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.Wallet
|
||||||
import org.bitcoins.wallet.sync.WalletSync
|
import org.bitcoins.wallet.sync.WalletSync
|
||||||
import grizzled.slf4j.Logging
|
|
||||||
|
|
||||||
import scala.concurrent.{ExecutionContext, Future}
|
import scala.concurrent.{ExecutionContext, Future}
|
||||||
|
|
||||||
@ -176,6 +187,57 @@ abstract class SyncUtil extends Logging {
|
|||||||
getBlockFunc = SyncUtil.getBlockFunc(bitcoind)
|
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
|
object SyncUtil extends SyncUtil
|
||||||
|
@ -2,8 +2,23 @@ package org.bitcoins.testkit.chain.fixture
|
|||||||
|
|
||||||
import org.bitcoins.chain.blockchain.ChainHandler
|
import org.bitcoins.chain.blockchain.ChainHandler
|
||||||
import org.bitcoins.rpc.client.common.BitcoindRpcClient
|
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 */
|
sealed trait BitcoindChainHandlerViaRpc {
|
||||||
case class 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,
|
bitcoindRpc: BitcoindRpcClient,
|
||||||
chainHandler: ChainHandler)
|
chainHandler: ChainHandler)
|
||||||
|
extends BitcoindChainHandlerViaRpc
|
||||||
|
|
||||||
|
case class BitcoindV19ChainHandler(
|
||||||
|
override val bitcoindRpc: BitcoindV19RpcClient,
|
||||||
|
chainHandler: ChainHandler)
|
||||||
|
extends BitcoindChainHandlerViaRpc
|
||||||
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,6 @@ import org.bitcoins.core.currency._
|
|||||||
import org.bitcoins.core.gcs.FilterType
|
import org.bitcoins.core.gcs.FilterType
|
||||||
import org.bitcoins.core.util.FutureUtil
|
import org.bitcoins.core.util.FutureUtil
|
||||||
import org.bitcoins.core.wallet.utxo.TxoState
|
import org.bitcoins.core.wallet.utxo.TxoState
|
||||||
import org.bitcoins.testkit.rpc.CachedBitcoindV19
|
|
||||||
import org.bitcoins.testkit.wallet.{
|
import org.bitcoins.testkit.wallet.{
|
||||||
BitcoinSWalletTestCachedBitcoinV19,
|
BitcoinSWalletTestCachedBitcoinV19,
|
||||||
WalletWithBitcoindV19
|
WalletWithBitcoindV19
|
||||||
@ -14,9 +13,7 @@ import org.scalatest.{FutureOutcome, Outcome}
|
|||||||
|
|
||||||
import scala.concurrent.Future
|
import scala.concurrent.Future
|
||||||
|
|
||||||
class ProcessBlockTest
|
class ProcessBlockTest extends BitcoinSWalletTestCachedBitcoinV19 {
|
||||||
extends BitcoinSWalletTestCachedBitcoinV19
|
|
||||||
with CachedBitcoindV19 {
|
|
||||||
|
|
||||||
override type FixtureParam = WalletWithBitcoindV19
|
override type FixtureParam = WalletWithBitcoindV19
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user