2024 03 24 v21 rpc refactor (#5494)

* WIP: Consolidate V19FilterRpc into BlockchainRpc

* Implement ChainApi.getFilterHeader() with bitcoind

* Make {BitcoindV22RpcClient,BitcoindV23RpcClient,BitcoindV24RpcClient} extend BitcoindRpcClient directly

* Fix MiningRpcTest

* Remove cast in BitcoindBackendTest
This commit is contained in:
Chris Stewart 2024-03-26 13:04:26 -05:00 committed by GitHub
parent 00b969b058
commit d162242a39
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 221 additions and 394 deletions

View file

@ -465,8 +465,10 @@ case class GetBlockFilterResult(
header: DoubleSha256DigestBE)
extends BlockchainResult {
def filterDb(height: Int): CompactFilterDb = {
CompactFilterDbHelper.fromGolombFilter(filter, header, height)
def filterDb(
height: Int,
blockHashBE: DoubleSha256DigestBE): CompactFilterDb = {
CompactFilterDbHelper.fromGolombFilter(filter, blockHashBE, height)
}
}

View file

@ -22,8 +22,7 @@ import org.bitcoins.core.protocol.transaction.Transaction
import org.bitcoins.core.util.FutureUtil
import org.bitcoins.crypto.DoubleSha256DigestBE
import org.bitcoins.dlc.wallet.DLCWallet
import org.bitcoins.rpc.client.common.BitcoindRpcClient
import org.bitcoins.rpc.client.v19.V19BlockFilterRpc
import org.bitcoins.rpc.client.common.{BitcoindRpcClient, BlockchainRpc}
import org.bitcoins.rpc.config.ZmqConfig
import org.bitcoins.rpc.util.BitcoindStreamUtil
import org.bitcoins.wallet.Wallet
@ -173,7 +172,7 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger {
hasFilters <- hasFiltersF
} yield {
if (hasFilters) {
filterSyncSink(bitcoind.asInstanceOf[V19BlockFilterRpc], wallet)
filterSyncSink(bitcoind, wallet)
} else {
Flow[DoubleSha256DigestBE]
.batch(100, hash => Vector(hash))(_ :+ _)
@ -296,11 +295,10 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger {
}
private def filterSyncSink(
bitcoindRpcClient: V19BlockFilterRpc,
wallet: NeutrinoHDWalletApi)(implicit system: ActorSystem): Sink[
bitcoindRpcClient: BlockchainRpc,
wallet: NeutrinoHDWalletApi)(implicit ec: ExecutionContext): Sink[
DoubleSha256DigestBE,
Future[NeutrinoHDWalletApi]] = {
import system.dispatcher
val numParallelism = FutureUtil.getParallelism
val sink: Sink[DoubleSha256DigestBE, Future[NeutrinoHDWalletApi]] =

View file

@ -2,12 +2,8 @@ package org.bitcoins.rpc.client.common
import org.apache.pekko.actor.ActorSystem
import org.bitcoins.commons.util.BitcoinSLogger
import org.bitcoins.core.api.chain.db.{
BlockHeaderDb,
CompactFilterDb,
CompactFilterHeaderDb
}
import org.bitcoins.core.api.chain.{ChainApi, ChainQueryApi, FilterSyncMarker}
import org.bitcoins.core.api.chain.db.BlockHeaderDb
import org.bitcoins.core.api.chain.{ChainApi, FilterSyncMarker}
import org.bitcoins.core.api.feeprovider.FeeRateApi
import org.bitcoins.core.api.node.NodeApi
import org.bitcoins.core.gcs.FilterHeader
@ -18,7 +14,7 @@ import org.bitcoins.core.protocol.transaction.Transaction
import org.bitcoins.core.util.{FutureUtil, NetworkUtil}
import org.bitcoins.core.wallet.fee.FeeUnit
import org.bitcoins.crypto.{DoubleSha256DigestBE, StringFactory}
import org.bitcoins.rpc.client.v19.V19BlockFilterRpc
import org.bitcoins.rpc.client.v18.V18AssortedRpc
import org.bitcoins.rpc.client.v20.{V20AssortedRpc, V20MultisigRpc}
import org.bitcoins.rpc.client.v21.BitcoindV21RpcClient
import org.bitcoins.rpc.client.v22.BitcoindV22RpcClient
@ -59,7 +55,8 @@ class BitcoindRpcClient(override val instance: BitcoindInstance)(implicit
with WalletRpc
with PsbtRpc
with UtilRpc
with V19BlockFilterRpc
with V18AssortedRpc
with DescriptorRpc
with V20MultisigRpc
with V20AssortedRpc {
@ -100,10 +97,6 @@ class BitcoindRpcClient(override val instance: BitcoindInstance)(implicit
getBlockHeader(blockHash).map(header => Some(header.confirmations))
}
/** Gets the number of compact filters in the database */
override def getFilterCount(): Future[Int] = Future.failed(
new UnsupportedOperationException(s"Not implemented: getFilterCount"))
/** Returns the block height of the given block stamp */
override def getHeightByBlockStamp(blockStamp: BlockStamp): Future[Int] =
blockStamp match {
@ -116,10 +109,6 @@ class BitcoindRpcClient(override val instance: BitcoindInstance)(implicit
new UnsupportedOperationException(s"Not implemented: $blockTime"))
}
override def getFiltersBetweenHeights(
startHeight: Int,
endHeight: Int): Future[Vector[ChainQueryApi.FilterResponse]] = ???
/** Gets the block height of the closest block to the given time */
override def epochSecondToBlockHeight(time: Long): Future[Int] = {
require(time >= 1231006505L,
@ -248,41 +237,6 @@ class BitcoindRpcClient(override val instance: BitcoindInstance)(implicit
blockHash: DoubleSha256DigestBE): Future[ChainApi] =
Future.successful(this)
override def getFilterHeaderCount(): Future[Int] = ???
override def getFilterHeadersAtHeight(
height: Int): Future[Vector[CompactFilterHeaderDb]] =
filterHeadersUnsupported
override def getBestFilterHeader(): Future[Option[CompactFilterHeaderDb]] =
filterHeadersUnsupported
override def getFilterHeader(
blockHash: DoubleSha256DigestBE): Future[Option[CompactFilterHeaderDb]] =
filterHeadersUnsupported
override def getBestFilter(): Future[Option[CompactFilterDb]] = ???
override def getFilter(
hash: DoubleSha256DigestBE): Future[Option[CompactFilterDb]] = ???
override def getFiltersAtHeight(
height: Int): Future[Vector[CompactFilterDb]] = filterHeadersUnsupported
protected def filtersUnsupported: Future[Nothing] = {
version.map { v =>
throw new UnsupportedOperationException(
s"Bitcoin Core $v does not support block filters")
}
}
protected def filterHeadersUnsupported: Future[Nothing] = {
version.map { v =>
throw new UnsupportedOperationException(
s"Bitcoin Core $v does not support block filters headers through the rpc")
}
}
def generate(numBlocks: Int): Future[Vector[DoubleSha256DigestBE]] = {
for {
addr <- getNewAddress

View file

@ -2,18 +2,27 @@ package org.bitcoins.rpc.client.common
import org.bitcoins.commons.jsonmodels.bitcoind._
import org.bitcoins.commons.serializers.JsonSerializers._
import org.bitcoins.core.api.chain.{ChainApi, ChainQueryApi}
import org.bitcoins.core.api.chain.ChainQueryApi.FilterResponse
import org.bitcoins.core.api.chain.db.{
CompactFilterDb,
CompactFilterHeaderDb,
CompactFilterHeaderDbHelper
}
import org.bitcoins.core.gcs.{BlockFilter, FilterHeader, FilterType}
import org.bitcoins.core.protocol.blockchain.{Block, BlockHeader}
import org.bitcoins.core.util.FutureUtil
import org.bitcoins.crypto.{DoubleSha256Digest, DoubleSha256DigestBE}
import org.bitcoins.rpc.client.common.BitcoindVersion._
import play.api.libs.json.{JsBoolean, JsNumber, JsString}
import play.api.libs.json.{JsBoolean, JsNumber, JsString, Json, Reads}
import scala.concurrent.Future
/** RPC calls related to querying the state of the blockchain
*/
trait BlockchainRpc { self: Client =>
trait BlockchainRpc extends ChainApi { self: Client =>
def getBestBlockHash(): Future[DoubleSha256DigestBE] = {
override def getBestBlockHash(): Future[DoubleSha256DigestBE] = {
bitcoindCall[DoubleSha256DigestBE]("getbestblockhash")
}
@ -36,7 +45,7 @@ trait BlockchainRpc { self: Client =>
}
}
def getBlockCount(): Future[Int] = {
override def getBlockCount(): Future[Int] = {
bitcoindCall[Int]("getblockcount")
}
@ -261,4 +270,134 @@ trait BlockchainRpc { self: Client =>
def syncWithValidationInterfaceQueue(): Future[Unit] = {
bitcoindCall[Unit](command = "syncwithvalidationinterfacequeue", List.empty)
}
/** This is needed because we need the block hash to create a GolombFilter.
* We use an intermediary data type to hold our data so we can add the block hash
* we were given after the RPC call
*/
private case class TempBlockFilterResult(
filter: String,
header: DoubleSha256DigestBE)
implicit
private val tempBlockFilterResultReads: Reads[TempBlockFilterResult] =
Json.reads[TempBlockFilterResult]
def getBlockFilter(
blockhash: DoubleSha256DigestBE,
filtertype: FilterType): Future[GetBlockFilterResult] = {
bitcoindCall[TempBlockFilterResult](
"getblockfilter",
List(JsString(blockhash.hex), JsString(filtertype.toString.toLowerCase)))
.map { tempBlockFilterResult =>
GetBlockFilterResult(
BlockFilter.fromHex(tempBlockFilterResult.filter, blockhash.flip),
tempBlockFilterResult.header)
}
}
override def getFiltersBetweenHeights(
startHeight: Int,
endHeight: Int): Future[Vector[ChainQueryApi.FilterResponse]] = {
val allHeights = startHeight.to(endHeight)
def f(range: Vector[Int]): Future[Vector[FilterResponse]] = {
val filterFs = range.map { height =>
for {
hash <- getBlockHash(height)
filter <- getBlockFilter(hash, FilterType.Basic)
} yield {
FilterResponse(filter.filter, hash, height)
}
}
Future.sequence(filterFs)
}
FutureUtil.batchAndSyncExecute(elements = allHeights.toVector,
f = f,
batchSize = FutureUtil.getParallelism)
}
override def getFilterCount(): Future[Int] = getBlockCount()
override def getFilterHeaderCount(): Future[Int] = getBlockCount()
override def getBestFilterHeader(): Future[Option[CompactFilterHeaderDb]] = {
for {
height <- getFilterHeaderCount()
blockHash <- getBlockHash(height)
fhOpt <- getFilterHeader(blockHash)
} yield fhOpt
}
override def getFilterHeader(blockHash: DoubleSha256DigestBE): Future[
Option[CompactFilterHeaderDb]] = {
for {
blockHeaderOpt <- getHeader(blockHash)
(filterOpt, prevFilterOpt) <- blockHeaderOpt match {
case Some(blockHeader) =>
val fOptF = getFilter(blockHeader.hashBE)
val prevOptF = getFilter(blockHeader.previousBlockHashBE)
fOptF.flatMap(f => prevOptF.map(p => (f, p)))
case None => Future.successful((None, None))
}
} yield {
(filterOpt, prevFilterOpt) match {
case (Some(filter), Some(prevFilter)) =>
val fh = FilterHeader(filter.hashBE, prevFilter.hashBE)
val c = CompactFilterHeaderDbHelper.fromFilterHeader(
filterHeader = fh,
blockHash = blockHash,
height = filter.height)
Some(c)
case (Some(filter), None) =>
//must be genesis filter
val fh = FilterHeader(filter.hashBE, DoubleSha256DigestBE.empty)
val c = CompactFilterHeaderDbHelper.fromFilterHeader(
filterHeader = fh,
blockHash = blockHash,
height = filter.height)
Some(c)
case (None, Some(_)) =>
//could find previous filter, but couldn't find compact filter?
None
case (None, None) => None
}
}
}
override def getFilterHeadersAtHeight(
height: Int): Future[Vector[CompactFilterHeaderDb]] = {
getBlockHash(height)
.flatMap { blockHashBE =>
getFilterHeader(blockHashBE)
}
.map(_.toVector)
}
override def getFilter(
hash: DoubleSha256DigestBE): Future[Option[CompactFilterDb]] = {
for {
header <- getBlockHeader(hash)
filter <- getBlockFilter(hash, FilterType.Basic)
} yield Some(filter.filterDb(header.height, header.hash))
}
override def getFiltersAtHeight(
height: Int): Future[Vector[CompactFilterDb]] = {
for {
hash <- getBlockHash(height)
filter <- getBlockFilter(hash, FilterType.Basic)
} yield Vector(filter.filterDb(height, hash))
}
override def getBestFilter(): Future[Option[CompactFilterDb]] = {
for {
filterCount <- getFilterCount()
blockHashBE <- getBlockHash(filterCount)
filterOpt <- getFilter(blockHashBE)
} yield {
filterOpt
}
}
}

View file

@ -506,4 +506,37 @@ trait WalletRpc { self: Client =>
uriExtensionOpt = walletNameOpt.map(walletExtension)
)
}
/** $signRawTx
*
* This RPC call signs the raw transaction with keys found in
* the Bitcoin Core wallet.
*/
def signRawTransactionWithWallet(
transaction: Transaction,
utxoDeps: Vector[RpcOpts.SignRawTransactionOutputParameter],
sigHash: HashType = HashType.sigHashAll
): Future[SignRawTransactionResult] =
bitcoindCall[SignRawTransactionResult]("signrawtransactionwithwallet",
List(JsString(transaction.hex),
Json.toJson(utxoDeps),
Json.toJson(sigHash)))
/** $signRawTx
*
* This RPC call signs the raw transaction with keys provided
* manually.
*/
def signRawTransactionWithKey(
transaction: Transaction,
keys: Vector[ECPrivateKey],
utxoDeps: Vector[RpcOpts.SignRawTransactionOutputParameter] =
Vector.empty,
sigHash: HashType = HashType.sigHashAll
): Future[SignRawTransactionResult] =
bitcoindCall[SignRawTransactionResult]("signrawtransactionwithkey",
List(JsString(transaction.hex),
Json.toJson(keys),
Json.toJson(utxoDeps),
Json.toJson(sigHash)))
}

View file

@ -1,44 +0,0 @@
package org.bitcoins.rpc.client.v19
import org.bitcoins.commons.jsonmodels.bitcoind.GetBlockFilterResult
import org.bitcoins.commons.serializers.JsonReaders.DoubleSha256DigestBEReads
import org.bitcoins.core.gcs.{BlockFilter, FilterType}
import org.bitcoins.crypto.DoubleSha256DigestBE
import org.bitcoins.rpc.client.common.Client
import play.api.libs.json._
import scala.concurrent.Future
/** Gets the BIP158 filter for the specified block.
* This RPC is only enabled if block filters have been created using the -blockfilterindex configuration option
* @see [[https://bitcoincore.org/en/doc/0.19.0/rpc/blockchain/getblockfilter]]
*/
trait V19BlockFilterRpc {
self: Client =>
/** This is needed because we need the block hash to create a GolombFilter.
* We use an intermediary data type to hold our data so we can add the block hash
* we were given after the RPC call
*/
private case class TempBlockFilterResult(
filter: String,
header: DoubleSha256DigestBE)
implicit
private val tempBlockFilterResultReads: Reads[TempBlockFilterResult] =
Json.reads[TempBlockFilterResult]
def getBlockFilter(
blockhash: DoubleSha256DigestBE,
filtertype: FilterType): Future[GetBlockFilterResult] = {
bitcoindCall[TempBlockFilterResult](
"getblockfilter",
List(JsString(blockhash.hex), JsString(filtertype.toString.toLowerCase)))
.map { tempBlockFilterResult =>
GetBlockFilterResult(
BlockFilter.fromHex(tempBlockFilterResult.filter, blockhash.flip),
tempBlockFilterResult.header)
}
}
}

View file

@ -1,26 +1,14 @@
package org.bitcoins.rpc.client.v21
import org.apache.pekko.actor.ActorSystem
import org.bitcoins.commons.jsonmodels.bitcoind._
import org.bitcoins.commons.serializers.JsonSerializers._
import org.bitcoins.commons.serializers.JsonWriters._
import org.bitcoins.core.api.chain.ChainQueryApi
import org.bitcoins.core.api.chain.ChainQueryApi.FilterResponse
import org.bitcoins.core.api.chain.db.CompactFilterDb
import org.bitcoins.core.gcs.FilterType
import org.bitcoins.core.protocol.transaction.Transaction
import org.bitcoins.core.util.FutureUtil
import org.bitcoins.crypto.{DoubleSha256DigestBE, ECPrivateKey, HashType}
import org.bitcoins.rpc.client.common.{
BitcoindRpcClient,
BitcoindVersion,
DescriptorRpc,
PsbtRpc
}
import org.bitcoins.rpc.client.v19.V19BlockFilterRpc
import org.bitcoins.rpc.client.v20.{V20AssortedRpc, V20MultisigRpc}
import org.bitcoins.rpc.config.BitcoindInstance
import play.api.libs.json._
import scala.concurrent.Future
import scala.util.Try
@ -32,87 +20,11 @@ class BitcoindV21RpcClient(override val instance: BitcoindInstance)(implicit
extends BitcoindRpcClient(instance)
with DescriptorRpc
with PsbtRpc
with V19BlockFilterRpc
with V20MultisigRpc
with V20AssortedRpc {
override def getFiltersBetweenHeights(
startHeight: Int,
endHeight: Int): Future[Vector[ChainQueryApi.FilterResponse]] = {
val allHeights = startHeight.to(endHeight)
def f(range: Vector[Int]): Future[Vector[FilterResponse]] = {
val filterFs = range.map { height =>
for {
hash <- getBlockHash(height)
filter <- getBlockFilter(hash, FilterType.Basic)
} yield {
FilterResponse(filter.filter, hash, height)
}
}
Future.sequence(filterFs)
}
FutureUtil.batchAndSyncExecute(elements = allHeights.toVector,
f = f,
batchSize = FutureUtil.getParallelism)
}
override def getFilterCount(): Future[Int] = getBlockCount()
override def getFilterHeaderCount(): Future[Int] = getBlockCount()
override def getFilter(
hash: DoubleSha256DigestBE): Future[Option[CompactFilterDb]] = {
for {
header <- getBlockHeader(hash)
filter <- getBlockFilter(hash, FilterType.Basic)
} yield Some(filter.filterDb(header.height))
}
override def getFiltersAtHeight(
height: Int): Future[Vector[CompactFilterDb]] = {
for {
hash <- getBlockHash(height)
filter <- getBlockFilter(hash, FilterType.Basic)
} yield Vector(filter.filterDb(height))
}
override lazy val version: Future[BitcoindVersion] =
Future.successful(BitcoindVersion.V21)
/** $signRawTx
*
* This RPC call signs the raw transaction with keys found in
* the Bitcoin Core wallet.
*/
def signRawTransactionWithWallet(
transaction: Transaction,
utxoDeps: Vector[RpcOpts.SignRawTransactionOutputParameter],
sigHash: HashType = HashType.sigHashAll
): Future[SignRawTransactionResult] =
bitcoindCall[SignRawTransactionResult]("signrawtransactionwithwallet",
List(JsString(transaction.hex),
Json.toJson(utxoDeps),
Json.toJson(sigHash)))
/** $signRawTx
*
* This RPC call signs the raw transaction with keys provided
* manually.
*/
def signRawTransactionWithKey(
transaction: Transaction,
keys: Vector[ECPrivateKey],
utxoDeps: Vector[RpcOpts.SignRawTransactionOutputParameter] =
Vector.empty,
sigHash: HashType = HashType.sigHashAll
): Future[SignRawTransactionResult] =
bitcoindCall[SignRawTransactionResult]("signrawtransactionwithkey",
List(JsString(transaction.hex),
Json.toJson(keys),
Json.toJson(utxoDeps),
Json.toJson(sigHash)))
}
object BitcoindV21RpcClient {

View file

@ -1,29 +0,0 @@
package org.bitcoins.rpc.client.v21
import org.bitcoins.commons.jsonmodels.bitcoind.GetWalletInfoResultPostV22
import org.bitcoins.commons.serializers.JsonSerializers.getWalletInfoResultReadsPostV22
import org.bitcoins.rpc.client.common.{Client, WalletRpc}
import org.bitcoins.rpc.client.v18.V18AssortedRpc
import org.bitcoins.rpc.client.v20.V20AssortedRpc
import play.api.libs.json.Json
import scala.concurrent.Future
trait V21AssortedRpc extends V18AssortedRpc with V20AssortedRpc with WalletRpc {
self: Client =>
private def getWalletInfo(
walletName: Option[String]): Future[GetWalletInfoResultPostV22] = {
bitcoindCall[GetWalletInfoResultPostV22]("getwalletinfo",
List(Json.toJson(walletName)))
}
override def getWalletInfo: Future[GetWalletInfoResultPostV22] = {
getWalletInfo(None)
}
override def getWalletInfo(
walletName: String): Future[GetWalletInfoResultPostV22] =
getWalletInfo(Some(walletName))
}

View file

@ -7,9 +7,7 @@ import org.bitcoins.rpc.client.common.{
DescriptorRpc,
PsbtRpc
}
import org.bitcoins.rpc.client.v19.V19BlockFilterRpc
import org.bitcoins.rpc.client.v20.V20MultisigRpc
import org.bitcoins.rpc.client.v21.BitcoindV21RpcClient
import org.bitcoins.rpc.config.BitcoindInstance
import scala.concurrent.Future
@ -19,17 +17,15 @@ import scala.util.Try
*/
class BitcoindV22RpcClient(override val instance: BitcoindInstance)(implicit
actorSystem: ActorSystem)
extends BitcoindV21RpcClient(instance)
extends BitcoindRpcClient(instance)
with DescriptorRpc
with PsbtRpc
with V19BlockFilterRpc
with V20MultisigRpc
with TestMempoolAcceptRpc
with V22AssortedRpc {
override lazy val version: Future[BitcoindVersion] = {
Future.successful(BitcoindVersion.V22)
}
}

View file

@ -2,7 +2,6 @@ package org.bitcoins.rpc.client.v23
import org.apache.pekko.actor.ActorSystem
import org.bitcoins.rpc.client.common.{BitcoindRpcClient, BitcoindVersion}
import org.bitcoins.rpc.client.v22.BitcoindV22RpcClient
import org.bitcoins.rpc.config.BitcoindInstance
import scala.concurrent.Future
@ -12,7 +11,7 @@ import scala.util.Try
*/
class BitcoindV23RpcClient(override val instance: BitcoindInstance)(implicit
actorSystem: ActorSystem)
extends BitcoindV22RpcClient(instance) {
extends BitcoindRpcClient(instance) {
override lazy val version: Future[BitcoindVersion] =
Future.successful(BitcoindVersion.V23)

View file

@ -9,7 +9,6 @@ import org.bitcoins.commons.serializers.JsonSerializers._
import org.bitcoins.core.currency.CurrencyUnit
import org.bitcoins.core.protocol.transaction.{Transaction, TransactionOutPoint}
import org.bitcoins.rpc.client.common.{BitcoindRpcClient, BitcoindVersion}
import org.bitcoins.rpc.client.v23.BitcoindV23RpcClient
import org.bitcoins.rpc.config.BitcoindInstance
import play.api.libs.json._
@ -20,7 +19,7 @@ import scala.util.Try
*/
class BitcoindV24RpcClient(override val instance: BitcoindInstance)(implicit
actorSystem: ActorSystem)
extends BitcoindV23RpcClient(instance) {
extends BitcoindRpcClient(instance) {
override lazy val version: Future[BitcoindVersion] =
Future.successful(BitcoindVersion.V24)

View file

@ -6,31 +6,28 @@ import org.bitcoins.core.gcs.FilterType
import org.bitcoins.core.protocol.blockchain.BlockHeader
import org.bitcoins.testkit.chain.SyncUtil
import org.bitcoins.testkit.chain.fixture.{
BitcoindBlockFilterRpcChainHandler,
ChainWithBitcoindBlockFilterRpcCachedUnitTest
BitcoindBaseVersionChainHandlerViaRpc,
ChainWithBitcoindNewestCachedUnitTest
}
import scala.concurrent.Future
class FilterSyncTest extends ChainWithBitcoindBlockFilterRpcCachedUnitTest {
class FilterSyncTest extends ChainWithBitcoindNewestCachedUnitTest {
behavior of "FilterSync"
it must "sync 1 filter header from an external data source" in { fixture =>
val BitcoindBlockFilterRpcChainHandler(bitcoind, chainHandler) = fixture
val BitcoindBaseVersionChainHandlerViaRpc(bitcoind, chainHandler) = fixture
val initFilterCountF = chainHandler.getFilterCount()
val initFilterHeaderCountF = chainHandler.getFilterHeaderCount()
val bitcoindFilterCountF = bitcoind.getFilterCount()
val initAssertionsF = for {
initFilterCount <- initFilterCountF
initFilterHeaderCount <- initFilterHeaderCountF
bitcoindFilterCount <- bitcoindFilterCountF
} yield {
assert(initFilterCount == bitcoindFilterCount)
assert(initFilterHeaderCount == bitcoindFilterCount)
assert(initFilterCount == 0)
assert(initFilterHeaderCount == 0)
}
val generated1BlockF = for {
@ -56,7 +53,7 @@ class FilterSyncTest extends ChainWithBitcoindBlockFilterRpcCachedUnitTest {
it must "sync a bunch of filter headers from an external data source" in {
fixture =>
val BitcoindBlockFilterRpcChainHandler(bitcoind, _) = fixture
val BitcoindBaseVersionChainHandlerViaRpc(bitcoind, _) = fixture
val numBlocks = 100
val generatedBlocksF = for {
@ -79,7 +76,7 @@ class FilterSyncTest extends ChainWithBitcoindBlockFilterRpcCachedUnitTest {
it must "be able to call filterSync() and not fail when nothing has happened" in {
fixture =>
val BitcoindBlockFilterRpcChainHandler(bitcoind, _) = fixture
val BitcoindBaseVersionChainHandlerViaRpc(bitcoind, _) = fixture
val generated1BlockF = for {
addr <- bitcoind.getNewAddress
@ -105,11 +102,11 @@ class FilterSyncTest extends ChainWithBitcoindBlockFilterRpcCachedUnitTest {
}
private def syncHelper(
bitcoindV19ChainHandler: BitcoindBlockFilterRpcChainHandler): Future[
bitcoindChainHandler: BitcoindBaseVersionChainHandlerViaRpc): Future[
ChainApi] = {
val filterType = FilterType.Basic
val BitcoindBlockFilterRpcChainHandler(bitcoind, chainHandler) =
bitcoindV19ChainHandler
val BitcoindBaseVersionChainHandlerViaRpc(bitcoind, chainHandler) =
bitcoindChainHandler
val getBestBlockHashFunc = SyncUtil.getBestBlockHashFunc(bitcoind)
val getBlockHeaderFunc = SyncUtil.getBlockHeaderFunc(bitcoind)

View file

@ -40,4 +40,5 @@ object FilterHeader {
prevHeaderHash: DoubleSha256DigestBE): FilterHeader = {
new FilterHeader(filterHash.flip, prevHeaderHash.flip)
}
}

View file

@ -18,7 +18,6 @@ import org.bitcoins.core.protocol.blockchain.{Block, BlockHeader}
import org.bitcoins.core.util.FutureUtil
import org.bitcoins.crypto.DoubleSha256DigestBE
import org.bitcoins.rpc.client.common.BitcoindRpcClient
import org.bitcoins.rpc.client.v19.V19BlockFilterRpc
import org.bitcoins.testkit.chain.ChainUnitTest.{
createChainHandler,
createChainHandlerCached
@ -692,50 +691,6 @@ object ChainUnitTest extends ChainVerificationLogger {
ChainSync.sync(chainHandler, getBlockHeaderFunc, getBestBlockHashFunc)
}
def createBitcoindBlockFilterRpcChainHandler(
bitcoindV19RpcClient: BitcoindRpcClient with V19BlockFilterRpc)(implicit
ec: ExecutionContext,
chainAppConfig: ChainAppConfig): Future[
BitcoindBlockFilterRpcChainHandler] = {
val chainApiWithBitcoindF = createChainApiWithBitcoindBlockFilterRpc(
bitcoindV19RpcClient)
//now sync the chain api to the bitcoind node
val syncedBitcoindWithChainHandlerF = for {
chainApiWithBitcoind <- chainApiWithBitcoindF
bitcoindWithChainHandler <- SyncUtil.syncBitcoindV19WithChainHandler(
chainApiWithBitcoind)
} yield bitcoindWithChainHandler
syncedBitcoindWithChainHandlerF
}
private def createChainApiWithBitcoindBlockFilterRpc(
bitcoind: BitcoindRpcClient with V19BlockFilterRpc)(implicit
ec: ExecutionContext,
chainAppConfig: ChainAppConfig): Future[
BitcoindBlockFilterRpcChainHandler] = {
val handlerWithGenesisHeaderF =
ChainUnitTest.setupHeaderTableWithGenesisHeader()
val chainHandlerF = handlerWithGenesisHeaderF.map(_._1)
chainHandlerF.map { handler =>
BitcoindBlockFilterRpcChainHandler(bitcoind, handler)
}
}
def destroyBitcoindV19ChainApi(
bitcoindV19ChainHandler: BitcoindBlockFilterRpcChainHandler)(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
*/

View file

@ -2,11 +2,7 @@ package org.bitcoins.testkit.chain
import org.apache.pekko.actor.ActorSystem
import org.bitcoins.chain.blockchain.ChainHandler
import org.bitcoins.chain.blockchain.sync.{
ChainSync,
FilterSync,
FilterWithHeaderHash
}
import org.bitcoins.chain.blockchain.sync.{FilterSync, FilterWithHeaderHash}
import org.bitcoins.chain.config.ChainAppConfig
import org.bitcoins.commons.jsonmodels.bitcoind.GetBlockFilterResult
import org.bitcoins.commons.util.BitcoinSLogger
@ -18,14 +14,9 @@ import org.bitcoins.core.protocol.blockchain.{Block, BlockHeader}
import org.bitcoins.core.protocol.transaction.Transaction
import org.bitcoins.core.util.FutureUtil
import org.bitcoins.crypto.DoubleSha256DigestBE
import org.bitcoins.rpc.client.common.BitcoindRpcClient
import org.bitcoins.rpc.client.v19.V19BlockFilterRpc
import org.bitcoins.rpc.client.common.{BitcoindRpcClient, BlockchainRpc}
import org.bitcoins.server.BitcoindRpcBackendUtil
import org.bitcoins.testkit.chain.fixture.{
BitcoindBaseVersionChainHandlerViaRpc,
BitcoindBlockFilterRpcChainHandler,
BitcoindChainHandlerViaRpc
}
import org.bitcoins.testkit.chain.fixture.BitcoindBaseVersionChainHandlerViaRpc
import org.bitcoins.wallet.Wallet
import org.bitcoins.wallet.sync.WalletSync
@ -48,9 +39,7 @@ abstract class SyncUtil extends BitcoinSLogger {
}
/** Creates a function that you can pass a block header to and it's return's it's [[GolombFilter]] */
def getFilterFunc(
bitcoind: V19BlockFilterRpc,
filterType: FilterType)(implicit
def getFilterFunc(bitcoind: BlockchainRpc, filterType: FilterType)(implicit
ec: ExecutionContext): BlockHeader => Future[FilterWithHeaderHash] = {
case header: BlockHeader =>
val prevFilterResultF =
@ -150,36 +139,14 @@ abstract class SyncUtil extends BitcoinSLogger {
} yield syncedWalletApi
}
/** 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: BitcoindBlockFilterRpcChainHandler)(implicit
def syncBitcoindWithChainHandler(
bitcoindWithChainHandler: BitcoindBaseVersionChainHandlerViaRpc)(implicit
ec: ExecutionContext,
chainAppConfig: ChainAppConfig): Future[
BitcoindBlockFilterRpcChainHandler] = {
BitcoindBaseVersionChainHandlerViaRpc] = {
val bitcoindV19 = bitcoindWithChainHandler.bitcoindRpc
val chainApiF = syncBitcoindWithChainHandler(bitcoindWithChainHandler)
.map(_.chainHandler)
@ -197,7 +164,7 @@ abstract class SyncUtil extends BitcoinSLogger {
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 BitcoindBlockFilterRpcChainHandler(
} yield BitcoindBaseVersionChainHandlerViaRpc(
bitcoindRpc = bitcoindWithChainHandler.bitcoindRpc,
chainHandler = filterSyncChainApi.asInstanceOf[ChainHandler])
}

View file

@ -2,7 +2,6 @@ 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.{V19BlockFilterRpc}
sealed trait BitcoindChainHandlerViaRpc {
def bitcoindRpc: BitcoindRpcClient
@ -17,8 +16,3 @@ case class BitcoindBaseVersionChainHandlerViaRpc(
bitcoindRpc: BitcoindRpcClient,
chainHandler: ChainHandler)
extends BitcoindChainHandlerViaRpc
case class BitcoindBlockFilterRpcChainHandler(
override val bitcoindRpc: BitcoindRpcClient with V19BlockFilterRpc,
chainHandler: ChainHandler)
extends BitcoindChainHandlerViaRpc

View file

@ -1,13 +1,8 @@
package org.bitcoins.testkit.chain.fixture
import org.bitcoins.rpc.client.common.BitcoindRpcClient
import org.bitcoins.rpc.client.v19.V19BlockFilterRpc
import org.bitcoins.testkit.chain.{ChainDbUnitTest, ChainUnitTest}
import org.bitcoins.testkit.rpc.{
CachedBitcoind,
CachedBitcoindBlockFilterRpcNewest,
CachedBitcoindNewest
}
import org.bitcoins.testkit.rpc.{CachedBitcoind, CachedBitcoindNewest}
import org.scalatest.{FutureOutcome, Outcome}
import scala.concurrent.Future
@ -51,40 +46,3 @@ trait ChainWithBitcoindNewestCachedUnitTest
super[ChainWithBitcoindUnitTest].afterAll()
}
}
/** Chain Unit test suite that has a cached bitcoind v19 instance */
trait ChainWithBitcoindBlockFilterRpcCachedUnitTest
extends ChainWithBitcoindUnitTest
with CachedBitcoindBlockFilterRpcNewest {
override type FixtureParam = BitcoindBlockFilterRpcChainHandler
override def withFixture(test: OneArgAsyncTest): FutureOutcome = {
val f: Future[Outcome] = for {
bitcoind <- cachedBitcoindWithFundsF
futOutcome = withBitcoindBlockFilterRpcChainHandlerViaRpc(test, bitcoind)
fut <- futOutcome.toFuture
} yield fut
new FutureOutcome(f)
}
def withBitcoindBlockFilterRpcChainHandlerViaRpc(
test: OneArgAsyncTest,
bitcoindRpcClient: BitcoindRpcClient
with V19BlockFilterRpc): FutureOutcome = {
val builder: () => Future[BitcoindBlockFilterRpcChainHandler] = { () =>
ChainUnitTest.createBitcoindBlockFilterRpcChainHandler(bitcoindRpcClient)
}
val destroy: BitcoindBlockFilterRpcChainHandler => Future[Unit] = {
case _: BitcoindBlockFilterRpcChainHandler =>
ChainUnitTest.destroyChainApi()
}
makeDependentFixture(builder, destroy)(test)
}
override def afterAll(): Unit = {
super[CachedBitcoindBlockFilterRpcNewest].afterAll()
super[ChainWithBitcoindUnitTest].afterAll()
}
}

View file

@ -2,7 +2,6 @@ package org.bitcoins.testkit.fixtures
import org.apache.pekko.actor.ActorSystem
import org.bitcoins.rpc.client.common.{BitcoindRpcClient, BitcoindVersion}
import org.bitcoins.rpc.client.v19.V19BlockFilterRpc
import org.bitcoins.testkit.rpc.BitcoindRpcTestUtil
import org.bitcoins.testkit.util.BitcoinSAsyncFixtureTest
import org.scalatest._
@ -98,14 +97,11 @@ object BitcoinSFixture {
def createBitcoindBlockFilterRpcWithFunds(
versionOpt: Option[BitcoindVersion] = None)(implicit
system: ActorSystem): Future[BitcoindRpcClient with V19BlockFilterRpc] = {
system: ActorSystem): Future[BitcoindRpcClient] = {
import system.dispatcher
for {
bitcoind <- createBitcoindWithFunds(versionOpt)
_ = require(
bitcoind.isInstanceOf[V19BlockFilterRpc],
s"Given version does not support block filter rpc, got=$versionOpt")
} yield bitcoind.asInstanceOf[BitcoindRpcClient with V19BlockFilterRpc]
} yield bitcoind
}
/** Creates a new bitcoind instance

View file

@ -839,6 +839,8 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger {
utxoDeps: Vector[RpcOpts.SignRawTransactionOutputParameter] = Vector.empty
): Future[SignRawTransactionResult] =
signer match {
case v24: BitcoindV24RpcClient =>
v24.signRawTransactionWithWallet(transaction, utxoDeps)
case v23: BitcoindV23RpcClient =>
v23.signRawTransactionWithWallet(transaction, utxoDeps)
case v22: BitcoindV22RpcClient =>

View file

@ -1,7 +1,6 @@
package org.bitcoins.testkit.rpc
import org.bitcoins.rpc.client.common.{BitcoindRpcClient, BitcoindVersion}
import org.bitcoins.rpc.client.v19.V19BlockFilterRpc
import org.bitcoins.rpc.client.v21.BitcoindV21RpcClient
import org.bitcoins.rpc.client.v22.BitcoindV22RpcClient
import org.bitcoins.rpc.client.v23.BitcoindV23RpcClient
@ -121,11 +120,11 @@ trait CachedBitcoindNewestNoP2pBlockFilters extends CachedBitcoindNewest {
}
trait CachedBitcoindBlockFilterRpcNewest
extends CachedBitcoindFunded[BitcoindRpcClient with V19BlockFilterRpc] {
extends CachedBitcoindFunded[BitcoindRpcClient] {
_: BitcoinSPekkoAsyncTest =>
override protected lazy val cachedBitcoindWithFundsF: Future[
BitcoindRpcClient with V19BlockFilterRpc] = {
BitcoindRpcClient] = {
val _ = isBitcoindUsed.set(true)
BitcoinSFixture
.createBitcoindBlockFilterRpcWithFunds(Some(BitcoindVersion.newest))

View file

@ -6,7 +6,6 @@ import org.bitcoins.core.api.wallet.SyncHeightDescriptor
import org.bitcoins.core.currency._
import org.bitcoins.core.gcs.FilterType
import org.bitcoins.core.wallet.utxo.TxoState
import org.bitcoins.rpc.client.v22.BitcoindV22RpcClient
import org.bitcoins.server.BitcoindRpcBackendUtil
import org.bitcoins.testkit.wallet._
import org.bitcoins.wallet.config.WalletAppConfig
@ -115,7 +114,7 @@ class BitcoindBackendTest extends WalletAppConfigWithBitcoindNewestFixtures {
it must "sync a filter" in { walletAppConfigWithBitcoind =>
val bitcoind =
walletAppConfigWithBitcoind.bitcoind.asInstanceOf[BitcoindV22RpcClient]
walletAppConfigWithBitcoind.bitcoind
val amountToSend = Bitcoins.one
for {
@ -151,7 +150,7 @@ class BitcoindBackendTest extends WalletAppConfigWithBitcoindNewestFixtures {
it must "sync a filter and update utxos to confirmed" in {
walletAppConfigWithBitcoind =>
val bitcoind =
walletAppConfigWithBitcoind.bitcoind.asInstanceOf[BitcoindV22RpcClient]
walletAppConfigWithBitcoind.bitcoind
val amountToSend = Bitcoins.one
for {