mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-01-19 05:43:51 +01:00
Bitcoind v0.20 updated rpcs & tests (#2061)
* Bitcoind v0.20 updated rpcs & tests * Test sorted multi
This commit is contained in:
parent
77ba9fd8b9
commit
920e30e5a2
@ -1,5 +1,7 @@
|
||||
package org.bitcoins.commons.jsonmodels.bitcoind
|
||||
|
||||
import java.nio.file.Path
|
||||
|
||||
import org.bitcoins.core.config.NetworkParameters
|
||||
import org.bitcoins.core.currency.Bitcoins
|
||||
import org.bitcoins.core.gcs.GolombFilter
|
||||
@ -10,6 +12,13 @@ import org.bitcoins.crypto.DoubleSha256DigestBE
|
||||
|
||||
sealed abstract class BlockchainResult
|
||||
|
||||
case class DumpTxOutSetResult(
|
||||
coins_written: Int,
|
||||
base_hash: DoubleSha256DigestBE,
|
||||
base_height: Int,
|
||||
path: Path)
|
||||
extends BlockchainResult
|
||||
|
||||
case class GetBlockResult(
|
||||
hash: DoubleSha256DigestBE,
|
||||
confirmations: Int,
|
||||
|
@ -21,8 +21,21 @@ import org.bitcoins.crypto.{
|
||||
|
||||
sealed abstract class WalletResult
|
||||
|
||||
case class MultiSigResult(address: BitcoinAddress, redeemScript: ScriptPubKey)
|
||||
extends WalletResult
|
||||
trait MultiSigResult extends WalletResult {
|
||||
def address: BitcoinAddress
|
||||
def redeemScript: ScriptPubKey
|
||||
}
|
||||
|
||||
case class MultiSigResultPreV20(
|
||||
address: BitcoinAddress,
|
||||
redeemScript: ScriptPubKey)
|
||||
extends MultiSigResult
|
||||
|
||||
case class MultiSigResultPostV20(
|
||||
address: BitcoinAddress,
|
||||
redeemScript: ScriptPubKey,
|
||||
descriptor: String)
|
||||
extends MultiSigResult
|
||||
|
||||
case class BumpFeeResult(
|
||||
txid: DoubleSha256DigestBE,
|
||||
|
@ -2,6 +2,7 @@ package org.bitcoins.commons.serializers
|
||||
|
||||
import java.io.File
|
||||
import java.net.{InetAddress, InetSocketAddress, URI}
|
||||
import java.nio.file.Path
|
||||
import java.time._
|
||||
import java.util.UUID
|
||||
|
||||
@ -607,6 +608,12 @@ object JsonReaders {
|
||||
SerializerUtil.processJsString[File](new File(_))(json)
|
||||
}
|
||||
|
||||
implicit object PathReads extends Reads[Path] {
|
||||
|
||||
override def reads(json: JsValue): JsResult[Path] =
|
||||
SerializerUtil.processJsString[Path](new File(_).toPath)(json)
|
||||
}
|
||||
|
||||
implicit object URIReads extends Reads[URI] {
|
||||
|
||||
override def reads(json: JsValue): JsResult[URI] =
|
||||
|
@ -211,6 +211,9 @@ object JsonSerializers {
|
||||
Json.reads[NodeBanPreV20]
|
||||
|
||||
// Blockchain Models
|
||||
implicit val dumpTxOutSetResultReads: Reads[DumpTxOutSetResult] =
|
||||
Json.reads[DumpTxOutSetResult]
|
||||
|
||||
implicit val getBlockResultReads: Reads[GetBlockResult] =
|
||||
Json.reads[GetBlockResult]
|
||||
|
||||
@ -288,8 +291,11 @@ object JsonSerializers {
|
||||
}
|
||||
|
||||
// Wallet Models
|
||||
implicit val multiSigReads: Reads[MultiSigResult] =
|
||||
Json.reads[MultiSigResult]
|
||||
implicit val multiSigPreV20Reads: Reads[MultiSigResultPreV20] =
|
||||
Json.reads[MultiSigResultPreV20]
|
||||
|
||||
implicit val multiSigPostV20Reads: Reads[MultiSigResultPostV20] =
|
||||
Json.reads[MultiSigResultPostV20]
|
||||
|
||||
implicit val bumpFeeReads: Reads[BumpFeeResult] = Json.reads[BumpFeeResult]
|
||||
|
||||
|
@ -0,0 +1,176 @@
|
||||
package org.bitcoins.rpc.v20
|
||||
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
|
||||
import org.bitcoins.commons.jsonmodels.bitcoind.RpcOpts.WalletFlag
|
||||
import org.bitcoins.commons.jsonmodels.bitcoind._
|
||||
import org.bitcoins.core.config.RegTest
|
||||
import org.bitcoins.core.gcs.{BlockFilter, FilterType}
|
||||
import org.bitcoins.core.protocol.transaction.EmptyTransaction
|
||||
import org.bitcoins.crypto.ECPublicKey
|
||||
import org.bitcoins.rpc.client.common.BitcoindVersion
|
||||
import org.bitcoins.rpc.client.v20.BitcoindV20RpcClient
|
||||
import org.bitcoins.testkit.rpc.BitcoindRpcTestUtil
|
||||
import org.bitcoins.testkit.util.BitcoindRpcTest
|
||||
|
||||
import scala.concurrent.Future
|
||||
|
||||
class BitcoindV20RpcClientTest extends BitcoindRpcTest {
|
||||
|
||||
lazy val clientPairF: Future[(BitcoindV20RpcClient, BitcoindV20RpcClient)] =
|
||||
BitcoindRpcTestUtil.createNodePairV20(clientAccum)
|
||||
|
||||
lazy val clientF: Future[BitcoindV20RpcClient] = clientPairF.map(_._1)
|
||||
|
||||
clientF.foreach(c => clientAccum.+=(c))
|
||||
|
||||
behavior of "BitcoindV20RpcClient"
|
||||
|
||||
it should "be able to start a V20 bitcoind instance" in {
|
||||
clientF.map { client =>
|
||||
assert(client.version == BitcoindVersion.V20)
|
||||
}
|
||||
}
|
||||
|
||||
it should "get a block filter given a block hash" in {
|
||||
for {
|
||||
(client, _) <- clientPairF
|
||||
blocks <- client.getNewAddress.flatMap(client.generateToAddress(1, _))
|
||||
blockFilter <- client.getBlockFilter(blocks.head, FilterType.Basic)
|
||||
|
||||
block <- client.getBlockRaw(blocks.head)
|
||||
txs <- Future.sequence(
|
||||
block.transactions
|
||||
.filterNot(_.isCoinbase)
|
||||
.map(tx => client.getTransaction(tx.txIdBE)))
|
||||
|
||||
prevFilter <- client.getBlockFilter(block.blockHeader.previousBlockHashBE,
|
||||
FilterType.Basic)
|
||||
} yield {
|
||||
val pubKeys = txs.flatMap(_.hex.outputs.map(_.scriptPubKey)).toVector
|
||||
val filter = BlockFilter(block, pubKeys)
|
||||
assert(filter.hash == blockFilter.filter.hash)
|
||||
assert(
|
||||
blockFilter.header == filter
|
||||
.getHeader(prevFilter.header.flip)
|
||||
.hash
|
||||
.flip)
|
||||
}
|
||||
}
|
||||
|
||||
it should "be able to get the balances" in {
|
||||
for {
|
||||
(client, _) <- clientPairF
|
||||
immatureBalance <- client.getBalances
|
||||
_ <- client.getNewAddress.flatMap(client.generateToAddress(1, _))
|
||||
newImmatureBalance <- client.getBalances
|
||||
} yield {
|
||||
val blockReward = 12.5
|
||||
assert(immatureBalance.mine.immature.toBigDecimal >= 0)
|
||||
assert(
|
||||
immatureBalance.mine.immature.toBigDecimal + blockReward == newImmatureBalance.mine.immature.toBigDecimal)
|
||||
}
|
||||
}
|
||||
|
||||
it should "be able to get blockchain info" in {
|
||||
for {
|
||||
(client, _) <- clientPairF
|
||||
info <- client.getBlockChainInfo
|
||||
bestHash <- client.getBestBlockHash
|
||||
} yield {
|
||||
assert(info.isInstanceOf[GetBlockChainInfoResultPostV19])
|
||||
val preV19Info = info.asInstanceOf[GetBlockChainInfoResultPostV19]
|
||||
assert(preV19Info.chain == RegTest)
|
||||
assert(preV19Info.softforks.size >= 5)
|
||||
assert(
|
||||
preV19Info.softforks.values.exists(_.isInstanceOf[Bip9SoftforkPostV19]))
|
||||
assert(preV19Info.bestblockhash == bestHash)
|
||||
}
|
||||
}
|
||||
|
||||
it should "be able to set the wallet flag 'avoid_reuse'" in {
|
||||
for {
|
||||
(client, _) <- clientPairF
|
||||
unspentPre <- client.listUnspent
|
||||
result <- client.setWalletFlag(WalletFlag.AvoidReuse, value = true)
|
||||
unspentPost <- client.listUnspent
|
||||
} yield {
|
||||
assert(result.flag_name == "avoid_reuse")
|
||||
assert(result.flag_state)
|
||||
assert(unspentPre.forall(utxo => utxo.reused.isEmpty))
|
||||
assert(unspentPost.forall(utxo => utxo.reused.isDefined))
|
||||
}
|
||||
}
|
||||
|
||||
it should "create a wallet with a passphrase" in {
|
||||
for {
|
||||
(client, _) <- clientPairF
|
||||
_ <- client.createWallet("suredbits", passphrase = "stackingsats")
|
||||
wallets <- client.listWallets
|
||||
} yield {
|
||||
assert(wallets.contains("suredbits"))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
it should "check to see if the utxoUpdate input has been updated" in {
|
||||
|
||||
val descriptor =
|
||||
"pk(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)"
|
||||
|
||||
val psbt =
|
||||
"cHNidP8BACoCAAAAAAFAQg8AAAAAABepFG6Rty1Vk+fUOR4v9E6R6YXDFkHwhwAAAAAAAA=="
|
||||
|
||||
for {
|
||||
(client, _) <- clientPairF
|
||||
result <- client.utxoUpdatePsbt(psbt, Seq(descriptor))
|
||||
} yield {
|
||||
assert(result.contains(psbt))
|
||||
}
|
||||
}
|
||||
|
||||
it should "correct create multisig and get its descriptor" in {
|
||||
val pubKey1 = ECPublicKey.freshPublicKey
|
||||
val pubKey2 = ECPublicKey.freshPublicKey
|
||||
|
||||
for {
|
||||
client <- clientF
|
||||
multiSigResult <- client.createMultiSig(2, Vector(pubKey1, pubKey2))
|
||||
} yield {
|
||||
// just validate we are able to receive a sane descriptor
|
||||
// no need to check checksum
|
||||
assert(
|
||||
multiSigResult.descriptor.startsWith(
|
||||
s"sh(multi(2,${pubKey1.hex},${pubKey2.hex}))#"))
|
||||
}
|
||||
}
|
||||
|
||||
it should "correctly dump tx out set" in {
|
||||
for {
|
||||
client <- clientF
|
||||
hash <- client.getBestBlockHash
|
||||
height <- client.getBestHashBlockHeight()
|
||||
result <- client.dumpTxOutSet(new File("utxo.dat").toPath)
|
||||
} yield {
|
||||
assert(Files.exists(result.path))
|
||||
// Mild clean up
|
||||
Files.delete(result.path)
|
||||
|
||||
assert(result.base_hash == hash)
|
||||
assert(result.base_height == height)
|
||||
assert(result.coins_written > 0)
|
||||
}
|
||||
}
|
||||
|
||||
it should "correct generate to a descriptor" in {
|
||||
// 2-of-2 multisig descriptor
|
||||
val descriptor =
|
||||
"sh(sortedmulti(2,023f720438186fbdfde0c0a403e770a0f32a2d198623a8a982c47b621f8b307640,03ed261094d609d5e02ba6553c2d91e4fd056006ce2fe64aace72b69cb5be3ab9c))#nj9wx7up"
|
||||
val numBlocks = 10
|
||||
for {
|
||||
client <- clientF
|
||||
hashes <- client.generateToDescriptor(numBlocks, descriptor)
|
||||
} yield assert(hashes.size == numBlocks)
|
||||
}
|
||||
}
|
@ -1,11 +1,16 @@
|
||||
package org.bitcoins.rpc.client.common
|
||||
|
||||
import org.bitcoins.commons.jsonmodels.bitcoind.MultiSigResult
|
||||
import org.bitcoins.commons.jsonmodels.bitcoind.RpcOpts.AddressType
|
||||
import org.bitcoins.commons.jsonmodels.bitcoind.{
|
||||
MultiSigResult,
|
||||
MultiSigResultPostV20,
|
||||
MultiSigResultPreV20
|
||||
}
|
||||
import org.bitcoins.commons.serializers.JsonSerializers._
|
||||
import org.bitcoins.commons.serializers.JsonWriters._
|
||||
import org.bitcoins.core.protocol.P2PKHAddress
|
||||
import org.bitcoins.crypto.ECPublicKey
|
||||
import org.bitcoins.rpc.client.common.BitcoindVersion._
|
||||
import play.api.libs.json.{JsArray, JsNumber, JsString, Json}
|
||||
|
||||
import scala.concurrent.Future
|
||||
@ -35,7 +40,12 @@ trait MultisigRpc { self: Client =>
|
||||
JsArray(keys.map(keyToString)),
|
||||
JsString(account)) ++ addressType.map(Json.toJson(_)).toList
|
||||
|
||||
bitcoindCall[MultiSigResult]("addmultisigaddress", params)
|
||||
self.version match {
|
||||
case V20 | Unknown =>
|
||||
bitcoindCall[MultiSigResultPostV20]("addmultisigaddress", params)
|
||||
case V16 | V17 | V18 | V19 | Experimental =>
|
||||
bitcoindCall[MultiSigResultPreV20]("addmultisigaddress", params)
|
||||
}
|
||||
}
|
||||
|
||||
def addMultiSigAddress(
|
||||
@ -65,9 +75,15 @@ trait MultisigRpc { self: Client =>
|
||||
def createMultiSig(
|
||||
minSignatures: Int,
|
||||
keys: Vector[ECPublicKey]): Future[MultiSigResult] = {
|
||||
bitcoindCall[MultiSigResult](
|
||||
"createmultisig",
|
||||
List(JsNumber(minSignatures), Json.toJson(keys.map(_.hex))))
|
||||
self.version match {
|
||||
case V20 | Unknown =>
|
||||
bitcoindCall[MultiSigResultPostV20](
|
||||
"createmultisig",
|
||||
List(JsNumber(minSignatures), Json.toJson(keys.map(_.hex))))
|
||||
case V16 | V17 | V18 | V19 | Experimental =>
|
||||
bitcoindCall[MultiSigResultPreV20](
|
||||
"createmultisig",
|
||||
List(JsNumber(minSignatures), Json.toJson(keys.map(_.hex))))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,12 +2,7 @@ package org.bitcoins.rpc.client.v20
|
||||
|
||||
import akka.actor.ActorSystem
|
||||
import org.bitcoins.commons.jsonmodels.bitcoind.RpcOpts.WalletFlag
|
||||
import org.bitcoins.commons.jsonmodels.bitcoind.{
|
||||
GetBalancesResult,
|
||||
RpcOpts,
|
||||
SetWalletFlagResult,
|
||||
SignRawTransactionResult
|
||||
}
|
||||
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
|
||||
@ -38,7 +33,9 @@ class BitcoindV20RpcClient(override val instance: BitcoindInstance)(implicit
|
||||
extends BitcoindRpcClient(instance)
|
||||
with DescriptorRpc
|
||||
with PsbtRpc
|
||||
with V19BlockFilterRpc {
|
||||
with V19BlockFilterRpc
|
||||
with V20MultisigRpc
|
||||
with V20AssortedRpc {
|
||||
|
||||
override def getFiltersBetweenHeights(
|
||||
startHeight: Int,
|
||||
|
@ -0,0 +1,31 @@
|
||||
package org.bitcoins.rpc.client.v20
|
||||
|
||||
import java.nio.file.Path
|
||||
|
||||
import org.bitcoins.commons.jsonmodels.bitcoind.DumpTxOutSetResult
|
||||
import org.bitcoins.commons.serializers.JsonSerializers._
|
||||
import org.bitcoins.crypto.DoubleSha256DigestBE
|
||||
import org.bitcoins.rpc.client.common.Client
|
||||
import play.api.libs.json.{JsNumber, JsString, Json}
|
||||
|
||||
import scala.concurrent.Future
|
||||
|
||||
/**
|
||||
* Assorted Rpc calls for Bitcoin V20
|
||||
*/
|
||||
trait V20AssortedRpc { self: Client =>
|
||||
|
||||
def dumpTxOutSet(path: Path): Future[DumpTxOutSetResult] = {
|
||||
bitcoindCall[DumpTxOutSetResult]("dumptxoutset",
|
||||
List(Json.toJson(path.toString)))
|
||||
}
|
||||
|
||||
def generateToDescriptor(
|
||||
numBlocks: Int,
|
||||
descriptor: String,
|
||||
maxTries: Long = 1000000): Future[Vector[DoubleSha256DigestBE]] = {
|
||||
bitcoindCall[Vector[DoubleSha256DigestBE]](
|
||||
"generatetodescriptor",
|
||||
List(JsNumber(numBlocks), JsString(descriptor), JsNumber(maxTries)))
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
package org.bitcoins.rpc.client.v20
|
||||
|
||||
import org.bitcoins.commons.jsonmodels.bitcoind.MultiSigResultPostV20
|
||||
import org.bitcoins.commons.jsonmodels.bitcoind.RpcOpts.AddressType
|
||||
import org.bitcoins.commons.serializers.JsonSerializers._
|
||||
import org.bitcoins.commons.serializers.JsonWriters._
|
||||
import org.bitcoins.core.protocol.P2PKHAddress
|
||||
import org.bitcoins.crypto.ECPublicKey
|
||||
import org.bitcoins.rpc.client.common.BitcoindVersion._
|
||||
import org.bitcoins.rpc.client.common.{Client, MultisigRpc}
|
||||
import play.api.libs.json.{JsArray, JsNumber, JsString, Json}
|
||||
|
||||
import scala.concurrent.Future
|
||||
|
||||
/**
|
||||
* This trait defines RPC calls related to
|
||||
* multisignature functionality in Bitcoin Core.
|
||||
*
|
||||
* @see [[https://en.bitcoin.it/wiki/Multisignature Bitcoin Wiki]]
|
||||
* article on multisignature.
|
||||
*/
|
||||
trait V20MultisigRpc extends MultisigRpc { self: Client =>
|
||||
|
||||
private def addMultiSigAddress(
|
||||
minSignatures: Int,
|
||||
keys: Vector[Either[ECPublicKey, P2PKHAddress]],
|
||||
account: String = "",
|
||||
addressType: Option[AddressType]): Future[MultiSigResultPostV20] = {
|
||||
def keyToString(key: Either[ECPublicKey, P2PKHAddress]): JsString =
|
||||
key match {
|
||||
case Right(k) => JsString(k.value)
|
||||
case Left(k) => JsString(k.hex)
|
||||
}
|
||||
|
||||
val params =
|
||||
List(JsNumber(minSignatures),
|
||||
JsArray(keys.map(keyToString)),
|
||||
JsString(account)) ++ addressType.map(Json.toJson(_)).toList
|
||||
|
||||
self.version match {
|
||||
case V20 | Unknown =>
|
||||
bitcoindCall[MultiSigResultPostV20]("addmultisigaddress", params)
|
||||
case version @ (V16 | V17 | V18 | V19 | Experimental) =>
|
||||
throw new RuntimeException(
|
||||
s"Cannot use v20MultisigRpc on an older version, got $version")
|
||||
}
|
||||
}
|
||||
|
||||
override def addMultiSigAddress(
|
||||
minSignatures: Int,
|
||||
keys: Vector[Either[ECPublicKey, P2PKHAddress]]): Future[
|
||||
MultiSigResultPostV20] =
|
||||
addMultiSigAddress(minSignatures, keys, addressType = None)
|
||||
|
||||
override def addMultiSigAddress(
|
||||
minSignatures: Int,
|
||||
keys: Vector[Either[ECPublicKey, P2PKHAddress]],
|
||||
account: String): Future[MultiSigResultPostV20] =
|
||||
addMultiSigAddress(minSignatures, keys, account, None)
|
||||
|
||||
override def addMultiSigAddress(
|
||||
minSignatures: Int,
|
||||
keys: Vector[Either[ECPublicKey, P2PKHAddress]],
|
||||
addressType: AddressType): Future[MultiSigResultPostV20] =
|
||||
addMultiSigAddress(minSignatures, keys, addressType = Some(addressType))
|
||||
|
||||
override def addMultiSigAddress(
|
||||
minSignatures: Int,
|
||||
keys: Vector[Either[ECPublicKey, P2PKHAddress]],
|
||||
account: String,
|
||||
addressType: AddressType): Future[MultiSigResultPostV20] =
|
||||
addMultiSigAddress(minSignatures, keys, account, Some(addressType))
|
||||
|
||||
override def createMultiSig(
|
||||
minSignatures: Int,
|
||||
keys: Vector[ECPublicKey]): Future[MultiSigResultPostV20] = {
|
||||
self.version match {
|
||||
case V20 | Unknown =>
|
||||
bitcoindCall[MultiSigResultPostV20](
|
||||
"createmultisig",
|
||||
List(JsNumber(minSignatures), Json.toJson(keys.map(_.hex))))
|
||||
case version @ (V16 | V17 | V18 | V19 | Experimental) =>
|
||||
throw new RuntimeException(
|
||||
s"Cannot use v20MultisigRpc on an older version, got $version")
|
||||
}
|
||||
}
|
||||
}
|
@ -55,6 +55,8 @@ sealed trait BitcoindInstance extends BitcoinSLogger {
|
||||
BitcoindVersion.V18
|
||||
case _: String if foundVersion.startsWith(BitcoindVersion.V19.toString) =>
|
||||
BitcoindVersion.V19
|
||||
case _: String if foundVersion.startsWith(BitcoindVersion.V20.toString) =>
|
||||
BitcoindVersion.V20
|
||||
case _: String => BitcoindVersion.Unknown
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ import org.bitcoins.rpc.client.v16.BitcoindV16RpcClient
|
||||
import org.bitcoins.rpc.client.v17.BitcoindV17RpcClient
|
||||
import org.bitcoins.rpc.client.v18.BitcoindV18RpcClient
|
||||
import org.bitcoins.rpc.client.v19.BitcoindV19RpcClient
|
||||
import org.bitcoins.rpc.client.v20.BitcoindV20RpcClient
|
||||
import org.bitcoins.rpc.config.{
|
||||
BitcoindAuthCredentials,
|
||||
BitcoindConfig,
|
||||
@ -606,7 +607,7 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger {
|
||||
BitcoindV19RpcClient.withActorSystem(
|
||||
BitcoindRpcTestUtil.v19Instance())
|
||||
case BitcoindVersion.V20 =>
|
||||
BitcoindV19RpcClient.withActorSystem(
|
||||
BitcoindV20RpcClient.withActorSystem(
|
||||
BitcoindRpcTestUtil.v20Instance())
|
||||
case BitcoindVersion.Experimental =>
|
||||
BitcoindV19RpcClient.withActorSystem(
|
||||
@ -693,6 +694,15 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger {
|
||||
system: ActorSystem): Future[(BitcoindV19RpcClient, BitcoindV19RpcClient)] =
|
||||
createNodePairInternal(BitcoindVersion.V19, clientAccum)
|
||||
|
||||
/**
|
||||
* Returns a pair of [[org.bitcoins.rpc.client.v20.BitcoindV20RpcClient BitcoindV20RpcClient]]
|
||||
* that are connected with some blocks in the chain
|
||||
*/
|
||||
def createNodePairV20(
|
||||
clientAccum: RpcClientAccum = Vector.newBuilder)(implicit
|
||||
system: ActorSystem): Future[(BitcoindV20RpcClient, BitcoindV20RpcClient)] =
|
||||
createNodePairInternal(BitcoindVersion.V20, clientAccum)
|
||||
|
||||
/**
|
||||
* Returns a triple of [[org.bitcoins.rpc.client.common.BitcoindRpcClient BitcoindRpcClient]]
|
||||
* that are connected with some blocks in the chain
|
||||
|
Loading…
Reference in New Issue
Block a user