mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-01-18 21:34:39 +01:00
Bitcoind v19 RPC (#910)
* bitcoind v19 new RPC calls and tests (#863) * bitcoind v19 new RPC calls and tests * Code review changes * Review part 2 * Rename variable to be more descriptive * Explanitory comment * Ignore broken test cases * Add missing signing functions * Add test to check avoid_reuse flag is on (#870) * Add test to check avoid_reuse flag is on * Add test to make sure flags weren't set * bitcoind v19 Update mempool RPCs and tests (#868) * Update mempool RPC calls to bitcoind v19 compatibility * Typo fix * Add parameter name to calls * Fix remaining rpc calls * Formatting * scaladoc for param * Change param to correct type * Clarify on scaladoc * Add missing fees parmater to mempool rpcs (#875) * Add weight field to mempool entries after v19 (#876) * Move DescriptorRpc to be able to be used by future versions of bitcoind (#878) * Add window_final_block_height to GetChainTxStatsResult (#880) * Add passphrase argument to createwallet for later versions (#883) * Add passphrase argument to createwallet for later versions * Scaladoc + empty passphrase requirement * Error message * Add new services names parameter to P2P rpcs (#874) * Add new services names parameter to P2P rpcs * Add ServiceIdentifier Reads * Add fallback case * Address review * Change to Try * Move PsbtRpc to be able to be used by future versions of bitcoind (#877) * Move PsbtRpc to be able to be used by future versions of bitcoind * Add test * Address comment * Enable bloom filters for v19 * Enable bip 61 for tests * Change to official binaries * Force v18 for Spv Tests * Remove unused config line
This commit is contained in:
parent
dd4787f2af
commit
5206353a4a
@ -7,3 +7,4 @@ zmppubrawtx=tcp://127.0.0.1:29001
|
||||
rpcport=18500
|
||||
port=9000
|
||||
daemon=1
|
||||
blockfilterindex=1
|
@ -5,11 +5,9 @@ import java.io.File
|
||||
import org.bitcoins.core.currency.Bitcoins
|
||||
import org.bitcoins.core.number.UInt32
|
||||
import org.bitcoins.core.protocol.script.ScriptSignature
|
||||
import org.bitcoins.core.protocol.transaction.{
|
||||
TransactionInput,
|
||||
TransactionOutPoint
|
||||
}
|
||||
import org.bitcoins.core.protocol.transaction.{TransactionInput, TransactionOutPoint}
|
||||
import org.bitcoins.rpc.client.common.BitcoindRpcClient
|
||||
import org.bitcoins.rpc.client.common.BitcoindVersion.V18
|
||||
import org.bitcoins.rpc.config.BitcoindInstance
|
||||
import org.bitcoins.testkit.rpc.BitcoindRpcTestUtil
|
||||
import org.bitcoins.testkit.util.BitcoindRpcTest
|
||||
@ -31,7 +29,7 @@ class MempoolRpcTest extends BitcoindRpcTest {
|
||||
|
||||
val instanceWithoutBroadcast =
|
||||
BitcoindInstance.fromConfig(configNoBroadcast,
|
||||
BitcoindRpcTestUtil.newestBitcoindBinary)
|
||||
BitcoindRpcTestUtil.getBinary(V18))
|
||||
|
||||
val clientWithoutBroadcast =
|
||||
BitcoindRpcClient.withActorSystem(instanceWithoutBroadcast)
|
||||
@ -137,7 +135,7 @@ class MempoolRpcTest extends BitcoindRpcTest {
|
||||
.createRawTransaction(Vector(input), Map(address2 -> Bitcoins.one))
|
||||
}
|
||||
signedTx <- BitcoindRpcTestUtil.signRawTransaction(client, createdTx)
|
||||
txid2 <- client.sendRawTransaction(signedTx.hex, allowHighFees = true)
|
||||
txid2 <- client.sendRawTransaction(signedTx.hex, maxfeerate = 0)
|
||||
|
||||
descendantsTxid1 <- client.getMemPoolDescendants(txid1)
|
||||
verboseDescendantsTxid1 <- client.getMemPoolDescendantsVerbose(txid1)
|
||||
@ -152,9 +150,9 @@ class MempoolRpcTest extends BitcoindRpcTest {
|
||||
verboseAncestorsTxid2 <- client.getMemPoolAncestorsVerbose(txid2)
|
||||
_ = {
|
||||
assert(ancestorsTxid2.head == txid1)
|
||||
val (txid, mempoolreults) = verboseAncestorsTxid2.head
|
||||
val (txid, mempoolresults) = verboseAncestorsTxid2.head
|
||||
assert(txid == txid1)
|
||||
assert(mempoolreults.descendantcount == 2)
|
||||
assert(mempoolresults.descendantcount == 2)
|
||||
}
|
||||
|
||||
} yield {
|
||||
|
@ -125,8 +125,7 @@ class RawTransactionRpcTest extends BitcoindRpcTest {
|
||||
|
||||
_ <- client.getNewAddress.flatMap(client.generateToAddress(100, _)) // Can't spend coinbase until depth 100
|
||||
|
||||
_ <- client.sendRawTransaction(signedTransaction.hex,
|
||||
allowHighFees = true)
|
||||
_ <- client.sendRawTransaction(signedTransaction.hex, maxfeerate = 0)
|
||||
} yield succeed
|
||||
}
|
||||
|
||||
|
@ -31,9 +31,9 @@ import scala.async.Async.{async, await}
|
||||
import scala.concurrent.Future
|
||||
|
||||
class WalletRpcTest extends BitcoindRpcTest {
|
||||
lazy val clientsF
|
||||
: Future[(BitcoindRpcClient, BitcoindRpcClient, BitcoindRpcClient)] =
|
||||
BitcoindRpcTestUtil.createNodeTripleV17(clientAccum = clientAccum)
|
||||
lazy val clientsF: Future[
|
||||
(BitcoindRpcClient, BitcoindRpcClient, BitcoindRpcClient)] =
|
||||
BitcoindRpcTestUtil.createNodeTripleV19(clientAccum = clientAccum)
|
||||
|
||||
// This client's wallet is encrypted
|
||||
lazy val walletClientF: Future[BitcoindRpcClient] = clientsF.flatMap { _ =>
|
||||
@ -514,7 +514,7 @@ class WalletRpcTest extends BitcoindRpcTest {
|
||||
client.createRawTransaction(inputs, outputs)
|
||||
}
|
||||
stx <- BitcoindRpcTestUtil.signRawTransaction(client, rawTx)
|
||||
txid <- client.sendRawTransaction(stx.hex, allowHighFees = true)
|
||||
txid <- client.sendRawTransaction(stx.hex, 0)
|
||||
tx <- client.getTransaction(txid)
|
||||
bumpedTx <- client.bumpFee(txid)
|
||||
} yield assert(tx.fee.get < bumpedTx.fee)
|
||||
|
@ -0,0 +1,111 @@
|
||||
package org.bitcoins.rpc.v19
|
||||
import org.bitcoins.core.gcs.{BlockFilter, FilterType}
|
||||
import org.bitcoins.rpc.client.common.BitcoindVersion
|
||||
import org.bitcoins.rpc.client.common.RpcOpts.WalletFlag
|
||||
import org.bitcoins.rpc.client.v19.BitcoindV19RpcClient
|
||||
import org.bitcoins.testkit.rpc.BitcoindRpcTestUtil
|
||||
import org.bitcoins.testkit.util.BitcoindRpcTest
|
||||
|
||||
import scala.concurrent.Future
|
||||
|
||||
class BitcoindV19RpcClientTest extends BitcoindRpcTest {
|
||||
lazy val clientF: Future[BitcoindV19RpcClient] = {
|
||||
val client = new BitcoindV19RpcClient(BitcoindRpcTestUtil.v19Instance())
|
||||
val clientIsStartedF = BitcoindRpcTestUtil.startServers(Vector(client))
|
||||
clientIsStartedF.map(_ => client)
|
||||
}
|
||||
lazy val clientPairF: Future[(BitcoindV19RpcClient, BitcoindV19RpcClient)] =
|
||||
BitcoindRpcTestUtil.createNodePairV19(clientAccum)
|
||||
|
||||
clientF.foreach(c => clientAccum.+=(c))
|
||||
|
||||
behavior of "BitcoindV19RpcClient"
|
||||
|
||||
it should "be able to start a V19 bitcoind instance" in {
|
||||
|
||||
clientF.map { client =>
|
||||
assert(client.version == BitcoindVersion.V19)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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 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=="
|
||||
val updatedF =
|
||||
clientF.flatMap(client => client.utxoUpdatePsbt(psbt, Seq(descriptor)))
|
||||
|
||||
updatedF.map { result =>
|
||||
assert(result.contains(psbt))
|
||||
}
|
||||
}
|
||||
}
|
@ -24,9 +24,10 @@ TaskKeys.downloadBitcoind := {
|
||||
Files.createDirectories(binaryDir)
|
||||
}
|
||||
|
||||
val experimentalVersion = "0.18.99"
|
||||
val experimentalVersion = "0.18.99" // TODO: change this when new version compiled on suredbits server
|
||||
|
||||
val versions = List("0.18.1", "0.17.0.1", "0.16.3", experimentalVersion)
|
||||
val versions =
|
||||
List("0.19.0.1", "0.18.1", "0.17.0.1", "0.16.3", experimentalVersion)
|
||||
|
||||
logger.debug(
|
||||
s"(Maybe) downloading Bitcoin Core binaries for versions: ${versions.mkString(",")}")
|
||||
|
@ -88,7 +88,7 @@ sealed trait BitcoindVersion
|
||||
object BitcoindVersion {
|
||||
|
||||
/** The newest version of `bitcoind` we support */
|
||||
val newest = V18
|
||||
val newest = V19
|
||||
|
||||
case object V16 extends BitcoindVersion {
|
||||
override def toString: String = "v0.16"
|
||||
@ -102,6 +102,10 @@ object BitcoindVersion {
|
||||
override def toString: String = "v0.18"
|
||||
}
|
||||
|
||||
case object V19 extends BitcoindVersion {
|
||||
override def toString: String = "v0.19"
|
||||
}
|
||||
|
||||
case object Experimental extends BitcoindVersion {
|
||||
override def toString: String = "v0.18.99"
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
package org.bitcoins.rpc.client.v18
|
||||
import org.bitcoins.rpc.client.common.Client
|
||||
package org.bitcoins.rpc.client.common
|
||||
|
||||
import org.bitcoins.rpc.jsonmodels.{
|
||||
DeriveAddressesResult,
|
||||
GetDescriptorInfoResult
|
||||
@ -14,15 +14,16 @@ import scala.concurrent.Future
|
||||
* @see [[https://bitcoincore.org/en/doc/0.18.0/rpc/util/deriveaddresses/]]
|
||||
* @see [[https://bitcoincore.org/en/doc/0.18.0/rpc/util/getdescriptorinfo/]]
|
||||
*/
|
||||
trait V18DescriptorRpc {
|
||||
trait DescriptorRpc {
|
||||
self: Client =>
|
||||
|
||||
def deriveAddresses(
|
||||
descriptor: String,
|
||||
range: Option[Vector[Double]]): Future[DeriveAddressesResult] = {
|
||||
bitcoindCall[DeriveAddressesResult](
|
||||
"deriveaddresses",
|
||||
List(JsString(descriptor), Json.toJson(range)))
|
||||
val params =
|
||||
if (range.isDefined) List(JsString(descriptor), Json.toJson(range))
|
||||
else List(JsString(descriptor))
|
||||
bitcoindCall[DeriveAddressesResult]("deriveaddresses", params)
|
||||
}
|
||||
|
||||
def getDescriptorInfo(descriptor: String): Future[GetDescriptorInfoResult] = {
|
@ -1,10 +1,15 @@
|
||||
package org.bitcoins.rpc.client.common
|
||||
|
||||
import org.bitcoins.core.crypto.{DoubleSha256Digest, DoubleSha256DigestBE}
|
||||
import org.bitcoins.rpc.client.common.BitcoindVersion._
|
||||
import org.bitcoins.rpc.jsonmodels.{
|
||||
GetMemPoolEntryResult,
|
||||
GetMemPoolEntryResultPostV19,
|
||||
GetMemPoolEntryResultPreV19,
|
||||
GetMemPoolInfoResult,
|
||||
GetMemPoolResult
|
||||
GetMemPoolResult,
|
||||
GetMemPoolResultPostV19,
|
||||
GetMemPoolResultPreV19
|
||||
}
|
||||
import org.bitcoins.rpc.serializers.JsonReaders._
|
||||
import org.bitcoins.rpc.serializers.JsonSerializers._
|
||||
@ -17,7 +22,7 @@ import scala.concurrent.Future
|
||||
* the mempool of a Bitcoin Core node. The
|
||||
* mempool contains all unconfirmed transactions.
|
||||
*/
|
||||
trait MempoolRpc { selc: Client =>
|
||||
trait MempoolRpc { self: Client =>
|
||||
|
||||
def getMemPoolAncestors(
|
||||
txid: DoubleSha256DigestBE): Future[Vector[DoubleSha256DigestBE]] = {
|
||||
@ -33,9 +38,17 @@ trait MempoolRpc { selc: Client =>
|
||||
|
||||
def getMemPoolAncestorsVerbose(txid: DoubleSha256DigestBE): Future[
|
||||
Map[DoubleSha256DigestBE, GetMemPoolResult]] = {
|
||||
bitcoindCall[Map[DoubleSha256DigestBE, GetMemPoolResult]](
|
||||
"getmempoolancestors",
|
||||
List(JsString(txid.hex), JsBoolean(true)))
|
||||
|
||||
self.version match {
|
||||
case V19 | Experimental | Unknown =>
|
||||
bitcoindCall[Map[DoubleSha256DigestBE, GetMemPoolResultPostV19]](
|
||||
"getmempoolancestors",
|
||||
List(JsString(txid.hex), JsBoolean(true)))
|
||||
case V16 | V17 | V18 =>
|
||||
bitcoindCall[Map[DoubleSha256DigestBE, GetMemPoolResultPreV19]](
|
||||
"getmempoolancestors",
|
||||
List(JsString(txid.hex), JsBoolean(true)))
|
||||
}
|
||||
}
|
||||
|
||||
def getMemPoolAncestorsVerbose(txid: DoubleSha256Digest): Future[
|
||||
@ -57,9 +70,16 @@ trait MempoolRpc { selc: Client =>
|
||||
|
||||
def getMemPoolDescendantsVerbose(txid: DoubleSha256DigestBE): Future[
|
||||
Map[DoubleSha256DigestBE, GetMemPoolResult]] = {
|
||||
bitcoindCall[Map[DoubleSha256DigestBE, GetMemPoolResult]](
|
||||
"getmempooldescendants",
|
||||
List(JsString(txid.hex), JsBoolean(true)))
|
||||
self.version match {
|
||||
case V19 | Experimental | Unknown =>
|
||||
bitcoindCall[Map[DoubleSha256DigestBE, GetMemPoolResultPostV19]](
|
||||
"getmempooldescendants",
|
||||
List(JsString(txid.hex), JsBoolean(true)))
|
||||
case V16 | V17 | V18 =>
|
||||
bitcoindCall[Map[DoubleSha256DigestBE, GetMemPoolResultPreV19]](
|
||||
"getmempooldescendants",
|
||||
List(JsString(txid.hex), JsBoolean(true)))
|
||||
}
|
||||
}
|
||||
|
||||
def getMemPoolDescendantsVerbose(txid: DoubleSha256Digest): Future[
|
||||
@ -69,8 +89,16 @@ trait MempoolRpc { selc: Client =>
|
||||
|
||||
def getMemPoolEntry(
|
||||
txid: DoubleSha256DigestBE): Future[GetMemPoolEntryResult] = {
|
||||
bitcoindCall[GetMemPoolEntryResult]("getmempoolentry",
|
||||
List(JsString(txid.hex)))
|
||||
|
||||
self.version match {
|
||||
case V19 | Experimental | Unknown =>
|
||||
bitcoindCall[GetMemPoolEntryResultPostV19]("getmempoolentry",
|
||||
List(JsString(txid.hex)))
|
||||
case V16 | V17 | V18 =>
|
||||
bitcoindCall[GetMemPoolEntryResultPreV19]("getmempoolentry",
|
||||
List(JsString(txid.hex)))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
def getMemPoolEntry(
|
||||
@ -89,9 +117,18 @@ trait MempoolRpc { selc: Client =>
|
||||
|
||||
def getRawMemPoolWithTransactions: Future[
|
||||
Map[DoubleSha256DigestBE, GetMemPoolResult]] = {
|
||||
bitcoindCall[Map[DoubleSha256DigestBE, GetMemPoolResult]](
|
||||
"getrawmempool",
|
||||
List(JsBoolean(true)))
|
||||
|
||||
self.version match {
|
||||
case V19 | Experimental | Unknown =>
|
||||
bitcoindCall[Map[DoubleSha256DigestBE, GetMemPoolResultPostV19]](
|
||||
"getrawmempool",
|
||||
List(JsBoolean(true)))
|
||||
case V16 | V17 | V18 =>
|
||||
bitcoindCall[Map[DoubleSha256DigestBE, GetMemPoolResultPreV19]](
|
||||
"getrawmempool",
|
||||
List(JsBoolean(true)))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
def saveMemPool(): Future[Unit] = {
|
||||
|
@ -1,19 +1,19 @@
|
||||
package org.bitcoins.rpc.client.v18
|
||||
package org.bitcoins.rpc.client.common
|
||||
|
||||
import org.bitcoins.rpc.client.common.Client
|
||||
import org.bitcoins.rpc.jsonmodels.AnalyzePsbtResult
|
||||
import org.bitcoins.rpc.serializers.JsonSerializers._
|
||||
import play.api.libs.json._
|
||||
import play.api.libs.json.{JsString, Json}
|
||||
|
||||
import scala.concurrent.Future
|
||||
|
||||
/**
|
||||
* Set of utilities to analyze, join, and update existing PSBTs
|
||||
*
|
||||
* @see [[https://bitcoincore.org/en/doc/0.18.0/rpc/rawtransactions/analyzepsbt/]]
|
||||
* @see [[https://bitcoincore.org/en/doc/0.18.0/rpc/rawtransactions/joinpsbts/]]
|
||||
* @see [[https://bitcoincore.org/en/doc/0.18.0/rpc/rawtransactions/utxoupdatepsbt/]]
|
||||
*/
|
||||
trait V18PsbtRpc {
|
||||
trait PsbtRpc {
|
||||
self: Client =>
|
||||
|
||||
def analyzePsbt(psbt: String): Future[AnalyzePsbtResult] = {
|
||||
@ -28,4 +28,9 @@ trait V18PsbtRpc {
|
||||
bitcoindCall[String]("utxoupdatepsbt", List(JsString(psbt)))
|
||||
}
|
||||
|
||||
def utxoUpdatePsbt(psbt: String, descriptors: Seq[String]): Future[String] = {
|
||||
bitcoindCall[String]("utxoupdatepsbt",
|
||||
List(JsString(psbt), Json.toJson(descriptors)))
|
||||
}
|
||||
|
||||
}
|
@ -4,6 +4,7 @@ import org.bitcoins.core.crypto.DoubleSha256DigestBE
|
||||
import org.bitcoins.core.currency.Bitcoins
|
||||
import org.bitcoins.core.protocol.BitcoinAddress
|
||||
import org.bitcoins.core.protocol.transaction.{Transaction, TransactionInput}
|
||||
import org.bitcoins.rpc.client.common.BitcoindVersion._
|
||||
import org.bitcoins.rpc.jsonmodels.{
|
||||
FundRawTransactionResult,
|
||||
GetRawTransactionResult,
|
||||
@ -88,12 +89,23 @@ trait RawTransactionRpc { self: Client =>
|
||||
bitcoindCall[Transaction]("getrawtransaction", params)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param maxfeerate Set to 0 if you want to enable allowhighfees
|
||||
*/
|
||||
def sendRawTransaction(
|
||||
transaction: Transaction,
|
||||
allowHighFees: Boolean = false): Future[DoubleSha256DigestBE] = {
|
||||
maxfeerate: Double = 0.10): Future[DoubleSha256DigestBE] = {
|
||||
|
||||
val feeParameter = self.version match {
|
||||
case V19 | Experimental | Unknown =>
|
||||
JsNumber(maxfeerate)
|
||||
case V16 | V17 | V18 =>
|
||||
JsBoolean(maxfeerate == 0)
|
||||
}
|
||||
|
||||
bitcoindCall[DoubleSha256DigestBE](
|
||||
"sendrawtransaction",
|
||||
List(JsString(transaction.hex), JsBoolean(allowHighFees)))
|
||||
List(JsString(transaction.hex), feeParameter))
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -127,6 +127,14 @@ object RpcOpts {
|
||||
|
||||
}
|
||||
|
||||
sealed trait WalletFlag
|
||||
|
||||
object WalletFlag {
|
||||
case object AvoidReuse extends WalletFlag {
|
||||
override def toString: String = "avoid_reuse"
|
||||
}
|
||||
}
|
||||
|
||||
sealed trait AddressType
|
||||
|
||||
object AddressType {
|
||||
|
@ -10,6 +10,7 @@ import org.bitcoins.core.currency.Bitcoins
|
||||
import org.bitcoins.core.protocol.BitcoinAddress
|
||||
import org.bitcoins.core.protocol.blockchain.MerkleBlock
|
||||
import org.bitcoins.core.protocol.transaction.Transaction
|
||||
import org.bitcoins.rpc.client.common.BitcoindVersion._
|
||||
import org.bitcoins.rpc.client.common.RpcOpts.AddressType
|
||||
import org.bitcoins.rpc.jsonmodels._
|
||||
import org.bitcoins.rpc.serializers.JsonSerializers._
|
||||
@ -185,13 +186,31 @@ trait WalletRpc { self: Client =>
|
||||
List(JsString(currentPassphrase), JsString(newPassphrase)))
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param blank Not available to versions before v19
|
||||
* @param passphrase Not available to versions before v19
|
||||
* @return
|
||||
*/
|
||||
def createWallet(
|
||||
walletName: String,
|
||||
disablePrivateKeys: Boolean = false): Future[CreateWalletResult] = {
|
||||
bitcoindCall[CreateWalletResult](
|
||||
"createwallet",
|
||||
List(JsString(walletName), Json.toJson(disablePrivateKeys)))
|
||||
}
|
||||
disablePrivateKeys: Boolean = false,
|
||||
blank: Boolean = false,
|
||||
passphrase: String = ""): Future[CreateWalletResult] =
|
||||
self.version match {
|
||||
case V19 | Experimental | Unknown =>
|
||||
bitcoindCall[CreateWalletResult]("createwallet",
|
||||
List(JsString(walletName),
|
||||
JsBoolean(disablePrivateKeys),
|
||||
JsBoolean(blank),
|
||||
JsString(passphrase)))
|
||||
case V16 | V17 | V18 =>
|
||||
require(passphrase.isEmpty,
|
||||
"passphrase should not be set for versions before v19")
|
||||
bitcoindCall[CreateWalletResult](
|
||||
"createwallet",
|
||||
List(JsString(walletName), JsBoolean(disablePrivateKeys)))
|
||||
}
|
||||
|
||||
def getAddressInfo(address: BitcoinAddress): Future[AddressInfoResult] = {
|
||||
bitcoindCall[AddressInfoResult]("getaddressinfo",
|
||||
|
@ -1,16 +1,28 @@
|
||||
package org.bitcoins.rpc.client.v18
|
||||
import akka.actor.ActorSystem
|
||||
import org.bitcoins.rpc.client.common.{
|
||||
BitcoindRpcClient,
|
||||
BitcoindVersion,
|
||||
DescriptorRpc,
|
||||
RpcOpts
|
||||
}
|
||||
import org.bitcoins.rpc.client.common.{BitcoindRpcClient, BitcoindVersion}
|
||||
import org.bitcoins.rpc.client.common.{
|
||||
BitcoindRpcClient,
|
||||
BitcoindVersion,
|
||||
PsbtRpc,
|
||||
RpcOpts
|
||||
}
|
||||
import org.bitcoins.rpc.config.BitcoindInstance
|
||||
|
||||
import scala.util.Try
|
||||
import org.bitcoins.core.protocol.transaction.Transaction
|
||||
import org.bitcoins.rpc.client.common.RpcOpts
|
||||
import org.bitcoins.core.crypto.ECPrivateKey
|
||||
import org.bitcoins.core.script.crypto.HashType
|
||||
import org.bitcoins.rpc.jsonmodels.SignRawTransactionResult
|
||||
import play.api.libs.json.Json
|
||||
import play.api.libs.json.JsString
|
||||
|
||||
import scala.concurrent.Future
|
||||
import org.bitcoins.rpc.serializers.JsonSerializers._
|
||||
import org.bitcoins.rpc.serializers.JsonWriters._
|
||||
@ -24,8 +36,8 @@ class BitcoindV18RpcClient(override val instance: BitcoindInstance)(
|
||||
implicit
|
||||
actorSystem: ActorSystem)
|
||||
extends BitcoindRpcClient(instance)
|
||||
with V18PsbtRpc
|
||||
with V18DescriptorRpc
|
||||
with DescriptorRpc
|
||||
with PsbtRpc
|
||||
with V18AssortedRpc {
|
||||
|
||||
override lazy val version: BitcoindVersion = BitcoindVersion.V18
|
||||
@ -83,7 +95,7 @@ object BitcoindV18RpcClient {
|
||||
/**
|
||||
* Creates an RPC client from the given instance,
|
||||
* together with the given actor system. This is for
|
||||
* advanced users, wher you need fine grained control
|
||||
* advanced users, where you need fine grained control
|
||||
* over the RPC client.
|
||||
*/
|
||||
def withActorSystem(instance: BitcoindInstance)(
|
||||
|
@ -0,0 +1,124 @@
|
||||
package org.bitcoins.rpc.client.v19
|
||||
|
||||
import akka.actor.ActorSystem
|
||||
import org.bitcoins.core.crypto.ECPrivateKey
|
||||
import org.bitcoins.core.protocol.transaction.Transaction
|
||||
import org.bitcoins.core.script.crypto.HashType
|
||||
import org.bitcoins.rpc.client.common.RpcOpts.WalletFlag
|
||||
import org.bitcoins.rpc.client.common.{
|
||||
BitcoindRpcClient,
|
||||
BitcoindVersion,
|
||||
DescriptorRpc,
|
||||
PsbtRpc,
|
||||
RpcOpts
|
||||
}
|
||||
import org.bitcoins.rpc.config.BitcoindInstance
|
||||
import org.bitcoins.rpc.jsonmodels.{
|
||||
GetBalancesResult,
|
||||
SetWalletFlagResult,
|
||||
SignRawTransactionResult
|
||||
}
|
||||
import play.api.libs.json.Json
|
||||
import play.api.libs.json.JsString
|
||||
import org.bitcoins.rpc.serializers.JsonSerializers._
|
||||
import org.bitcoins.rpc.serializers.JsonWriters._
|
||||
|
||||
import scala.concurrent.Future
|
||||
import scala.util.Try
|
||||
|
||||
/**
|
||||
* Class for creating a BitcoindV19 instance that can access RPCs
|
||||
*/
|
||||
class BitcoindV19RpcClient(override val instance: BitcoindInstance)(
|
||||
implicit
|
||||
actorSystem: ActorSystem)
|
||||
extends BitcoindRpcClient(instance)
|
||||
with DescriptorRpc
|
||||
with PsbtRpc
|
||||
with V19BlockFilterRpc {
|
||||
|
||||
override lazy val version: BitcoindVersion = BitcoindVersion.V19
|
||||
|
||||
/**
|
||||
* $signRawTx
|
||||
*
|
||||
* This RPC call signs the raw transaction with keys found in
|
||||
* the Bitcoin Core wallet.
|
||||
*/
|
||||
def signRawTransactionWithWallet(
|
||||
transaction: Transaction,
|
||||
utxoDeps: Vector[RpcOpts.SignRawTransactionOutputParameter] = Vector.empty,
|
||||
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)))
|
||||
|
||||
/**
|
||||
* Change the state of the given wallet flag for a wallet.
|
||||
*/
|
||||
def setWalletFlag(
|
||||
flag: WalletFlag,
|
||||
value: Boolean
|
||||
): Future[SetWalletFlagResult] =
|
||||
bitcoindCall[SetWalletFlagResult](
|
||||
"setwalletflag",
|
||||
List(JsString(flag.toString), Json.toJson(value)))
|
||||
|
||||
def getBalances: Future[GetBalancesResult] = {
|
||||
bitcoindCall[GetBalancesResult]("getbalances")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
object BitcoindV19RpcClient {
|
||||
|
||||
/**
|
||||
* Creates an RPC client from the given instance.
|
||||
*
|
||||
* Behind the scenes, we create an actor system for
|
||||
* you. You can use `withActorSystem` if you want to
|
||||
* manually specify an actor system for the RPC client.
|
||||
*/
|
||||
def apply(instance: BitcoindInstance): BitcoindV19RpcClient = {
|
||||
implicit val system =
|
||||
ActorSystem.create(BitcoindRpcClient.ActorSystemName)
|
||||
withActorSystem(instance)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an RPC client from the given instance,
|
||||
* together with the given actor system. This is for
|
||||
* advanced users, where you need fine grained control
|
||||
* over the RPC client.
|
||||
*/
|
||||
def withActorSystem(instance: BitcoindInstance)(
|
||||
implicit system: ActorSystem): BitcoindV19RpcClient =
|
||||
new BitcoindV19RpcClient(instance)(system)
|
||||
|
||||
def fromUnknownVersion(
|
||||
rpcClient: BitcoindRpcClient): Try[BitcoindV19RpcClient] =
|
||||
Try {
|
||||
new BitcoindV19RpcClient(rpcClient.instance)(rpcClient.system)
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package org.bitcoins.rpc.client.v19
|
||||
|
||||
import org.bitcoins.core.crypto.DoubleSha256DigestBE
|
||||
import org.bitcoins.core.gcs.{BlockFilter, FilterType}
|
||||
import org.bitcoins.rpc.client.common.Client
|
||||
import org.bitcoins.rpc.jsonmodels.GetBlockFilterResult
|
||||
import org.bitcoins.rpc.serializers.JsonReaders.DoubleSha256DigestBEReads
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -59,6 +59,8 @@ sealed trait BitcoindInstance extends BitcoinSLogger {
|
||||
BitcoindVersion.V17
|
||||
case _: String if foundVersion.startsWith(BitcoindVersion.V18.toString) =>
|
||||
BitcoindVersion.V18
|
||||
case _: String if foundVersion.startsWith(BitcoindVersion.V19.toString) =>
|
||||
BitcoindVersion.V19
|
||||
case _: String => BitcoindVersion.Unknown
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import org.bitcoins.core.number.{Int32, UInt32}
|
||||
import org.bitcoins.core.protocol.blockchain.BlockHeader
|
||||
import org.bitcoins.core.wallet.fee.BitcoinFeeUnit
|
||||
import org.bitcoins.core.config.NetworkParameters
|
||||
import org.bitcoins.core.gcs.GolombFilter
|
||||
|
||||
sealed abstract class BlockchainResult
|
||||
|
||||
@ -139,12 +140,30 @@ case class GetChainTxStatsResult(
|
||||
time: UInt32,
|
||||
txcount: Int,
|
||||
window_block_count: Int,
|
||||
window_final_block_height: Option[Int],
|
||||
window_tx_count: Option[Int],
|
||||
window_interval: Option[UInt32],
|
||||
txrate: Option[BigDecimal])
|
||||
extends BlockchainResult
|
||||
|
||||
case class GetMemPoolResult(
|
||||
sealed trait GetMemPoolResult extends BlockchainResult {
|
||||
def size: Int
|
||||
def fee: Option[Bitcoins]
|
||||
def modifiedfee: Option[Bitcoins]
|
||||
def time: UInt32
|
||||
def height: Int
|
||||
def descendantcount: Int
|
||||
def descendantsize: Int
|
||||
def descendantfees: Option[Bitcoins]
|
||||
def ancestorcount: Int
|
||||
def ancestorsize: Int
|
||||
def ancestorfees: Option[Bitcoins]
|
||||
def wtxid: DoubleSha256DigestBE
|
||||
def fees: FeeInfo
|
||||
def depends: Vector[DoubleSha256DigestBE]
|
||||
}
|
||||
|
||||
case class GetMemPoolResultPreV19(
|
||||
size: Int,
|
||||
fee: Option[Bitcoins],
|
||||
modifiedfee: Option[Bitcoins],
|
||||
@ -157,10 +176,54 @@ case class GetMemPoolResult(
|
||||
ancestorsize: Int,
|
||||
ancestorfees: Option[Bitcoins],
|
||||
wtxid: DoubleSha256DigestBE,
|
||||
fees: FeeInfo,
|
||||
depends: Vector[DoubleSha256DigestBE])
|
||||
extends BlockchainResult
|
||||
extends GetMemPoolResult
|
||||
|
||||
case class GetMemPoolEntryResult(
|
||||
case class GetMemPoolResultPostV19(
|
||||
vsize: Int,
|
||||
fee: Option[Bitcoins],
|
||||
modifiedfee: Option[Bitcoins],
|
||||
time: UInt32,
|
||||
height: Int,
|
||||
descendantcount: Int,
|
||||
descendantsize: Int,
|
||||
descendantfees: Option[Bitcoins],
|
||||
ancestorcount: Int,
|
||||
ancestorsize: Int,
|
||||
ancestorfees: Option[Bitcoins],
|
||||
wtxid: DoubleSha256DigestBE,
|
||||
fees: FeeInfo,
|
||||
depends: Vector[DoubleSha256DigestBE])
|
||||
extends GetMemPoolResult {
|
||||
override def size: Int = vsize
|
||||
}
|
||||
|
||||
case class FeeInfo(
|
||||
base: BitcoinFeeUnit,
|
||||
modified: BitcoinFeeUnit,
|
||||
ancestor: BitcoinFeeUnit,
|
||||
descendant: BitcoinFeeUnit
|
||||
)
|
||||
|
||||
sealed trait GetMemPoolEntryResult extends BlockchainResult {
|
||||
def size: Int
|
||||
def fee: Bitcoins
|
||||
def modifiedfee: Bitcoins
|
||||
def time: UInt32
|
||||
def height: Int
|
||||
def descendantcount: Int
|
||||
def descendantsize: Int
|
||||
def descendantfees: BitcoinFeeUnit
|
||||
def ancestorcount: Int
|
||||
def ancestorsize: Int
|
||||
def ancestorfees: BitcoinFeeUnit
|
||||
def wtxid: DoubleSha256DigestBE
|
||||
def fees: FeeInfo
|
||||
def depends: Option[Vector[DoubleSha256DigestBE]]
|
||||
}
|
||||
|
||||
case class GetMemPoolEntryResultPreV19(
|
||||
size: Int,
|
||||
fee: Bitcoins,
|
||||
modifiedfee: Bitcoins,
|
||||
@ -168,12 +231,34 @@ case class GetMemPoolEntryResult(
|
||||
height: Int,
|
||||
descendantcount: Int,
|
||||
descendantsize: Int,
|
||||
descendantfees: Bitcoins, // Should be BitcoinFeeUnit
|
||||
descendantfees: BitcoinFeeUnit,
|
||||
ancestorcount: Int,
|
||||
ancestorsize: Int,
|
||||
ancestorfees: Bitcoins, // Should be BitcoinFeeUnit
|
||||
ancestorfees: BitcoinFeeUnit,
|
||||
wtxid: DoubleSha256DigestBE,
|
||||
fees: FeeInfo,
|
||||
depends: Option[Vector[DoubleSha256DigestBE]])
|
||||
extends BlockchainResult
|
||||
extends GetMemPoolEntryResult
|
||||
|
||||
case class GetMemPoolEntryResultPostV19(
|
||||
vsize: Int,
|
||||
fee: Bitcoins,
|
||||
weight: Int,
|
||||
modifiedfee: Bitcoins,
|
||||
time: UInt32,
|
||||
height: Int,
|
||||
descendantcount: Int,
|
||||
descendantsize: Int,
|
||||
descendantfees: BitcoinFeeUnit,
|
||||
ancestorcount: Int,
|
||||
ancestorsize: Int,
|
||||
ancestorfees: BitcoinFeeUnit,
|
||||
wtxid: DoubleSha256DigestBE,
|
||||
fees: FeeInfo,
|
||||
depends: Option[Vector[DoubleSha256DigestBE]])
|
||||
extends GetMemPoolEntryResult {
|
||||
override def size: Int = vsize
|
||||
}
|
||||
|
||||
case class GetMemPoolInfoResult(
|
||||
size: Int,
|
||||
@ -202,3 +287,8 @@ case class GetTxOutSetInfoResult(
|
||||
disk_size: Int,
|
||||
total_amount: Bitcoins)
|
||||
extends BlockchainResult
|
||||
|
||||
case class GetBlockFilterResult(
|
||||
filter: GolombFilter,
|
||||
header: DoubleSha256DigestBE)
|
||||
extends BlockchainResult
|
||||
|
@ -4,6 +4,7 @@ import java.net.URI
|
||||
|
||||
import org.bitcoins.core.currency.Bitcoins
|
||||
import org.bitcoins.core.number.{UInt32, UInt64}
|
||||
import org.bitcoins.core.p2p.ServiceIdentifier
|
||||
import org.bitcoins.core.wallet.fee.SatoshisPerKiloByte
|
||||
|
||||
import scala.concurrent.duration.FiniteDuration
|
||||
@ -39,6 +40,7 @@ case class GetNetworkInfoResult(
|
||||
subversion: String,
|
||||
protocolversion: Int,
|
||||
localservices: String,
|
||||
localservicesnames: Option[Vector[ServiceIdentifier]],
|
||||
localrelay: Boolean,
|
||||
timeoffset: Int,
|
||||
networkactive: Boolean,
|
||||
@ -84,6 +86,7 @@ case class PeerNetworkInfo(
|
||||
addrbind: URI,
|
||||
addrlocal: Option[URI],
|
||||
services: String,
|
||||
servicesnames: Option[Vector[ServiceIdentifier]],
|
||||
relaytxes: Boolean,
|
||||
lastsend: UInt32,
|
||||
lastrecv: UInt32,
|
||||
|
@ -164,6 +164,7 @@ final case class DeriveAddressesResult(addresses: Vector[BitcoinAddress])
|
||||
|
||||
final case class GetDescriptorInfoResult(
|
||||
descriptor: String,
|
||||
checksum: Option[String],
|
||||
isrange: Boolean,
|
||||
issolvable: Boolean,
|
||||
hasprivatekeys: Boolean
|
||||
|
@ -50,6 +50,20 @@ case class GetTransactionResult(
|
||||
hex: Transaction)
|
||||
extends WalletResult
|
||||
|
||||
case class SetWalletFlagResult(
|
||||
flag_name: String,
|
||||
flag_state: Boolean,
|
||||
warnings: Option[String])
|
||||
extends WalletResult
|
||||
|
||||
case class GetBalancesResult(mine: BalanceInfo, watchonly: Option[BalanceInfo])
|
||||
extends WalletResult
|
||||
|
||||
case class BalanceInfo(
|
||||
trusted: Bitcoins,
|
||||
untrusted_pending: Bitcoins,
|
||||
immature: Bitcoins)
|
||||
|
||||
case class TransactionDetails(
|
||||
involvesWatchonly: Option[Boolean],
|
||||
account: Option[String],
|
||||
@ -102,7 +116,7 @@ case class RescanBlockChainResult(start_height: Int, stop_height: Int)
|
||||
case class ReceivedAddress(
|
||||
involvesWatchonly: Option[Boolean],
|
||||
address: BitcoinAddress,
|
||||
account: String,
|
||||
account: Option[String],
|
||||
amount: Bitcoins,
|
||||
confirmations: Int,
|
||||
label: String,
|
||||
@ -186,7 +200,8 @@ case class UnspentOutput(
|
||||
amount: Bitcoins,
|
||||
confirmations: Int,
|
||||
spendable: Boolean,
|
||||
solvable: Boolean)
|
||||
solvable: Boolean,
|
||||
reused: Option[Boolean])
|
||||
extends WalletResult
|
||||
|
||||
case class AddressInfoResult(
|
||||
|
@ -200,11 +200,21 @@ object JsonSerializers {
|
||||
implicit val getChainTxStatsResultReads: Reads[GetChainTxStatsResult] =
|
||||
Json.reads[GetChainTxStatsResult]
|
||||
|
||||
implicit val getMemPoolResultReads: Reads[GetMemPoolResult] =
|
||||
Json.reads[GetMemPoolResult]
|
||||
implicit val feeInfoReads: Reads[FeeInfo] = Json.reads[FeeInfo]
|
||||
|
||||
implicit val getMemPoolEntryResultReads: Reads[GetMemPoolEntryResult] =
|
||||
Json.reads[GetMemPoolEntryResult]
|
||||
implicit val getMemPoolResultPreV19Reads: Reads[GetMemPoolResultPreV19] =
|
||||
Json.reads[GetMemPoolResultPreV19]
|
||||
|
||||
implicit val getMemPoolResultPostV19Reads: Reads[GetMemPoolResultPostV19] =
|
||||
Json.reads[GetMemPoolResultPostV19]
|
||||
|
||||
implicit val getMemPoolEntryResultPreV19Reads: Reads[
|
||||
GetMemPoolEntryResultPreV19] =
|
||||
Json.reads[GetMemPoolEntryResultPreV19]
|
||||
|
||||
implicit val getMemPoolEntryResultPostV19Reads: Reads[
|
||||
GetMemPoolEntryResultPostV19] =
|
||||
Json.reads[GetMemPoolEntryResultPostV19]
|
||||
|
||||
implicit val getMemPoolInfoResultReads: Reads[GetMemPoolInfoResult] =
|
||||
Json.reads[GetMemPoolInfoResult]
|
||||
@ -230,6 +240,13 @@ object JsonSerializers {
|
||||
|
||||
implicit val bumpFeeReads: Reads[BumpFeeResult] = Json.reads[BumpFeeResult]
|
||||
|
||||
implicit val setWalletFlagResultReads: Reads[SetWalletFlagResult] =
|
||||
Json.reads[SetWalletFlagResult]
|
||||
|
||||
implicit val balanceInfoReads: Reads[BalanceInfo] = Json.reads[BalanceInfo]
|
||||
implicit val getBalancesResultReads: Reads[GetBalancesResult] =
|
||||
Json.reads[GetBalancesResult]
|
||||
|
||||
implicit val TransactionDetailsReads: Reads[TransactionDetails] =
|
||||
Json.reads[TransactionDetails]
|
||||
implicit val getTransactionResultReads: Reads[GetTransactionResult] =
|
||||
@ -443,14 +460,24 @@ object JsonSerializers {
|
||||
Json.reads[CreateWalletResult]
|
||||
|
||||
// Map stuff
|
||||
implicit def mapDoubleSha256DigestReads: Reads[
|
||||
Map[DoubleSha256Digest, GetMemPoolResult]] =
|
||||
Reads.mapReads[DoubleSha256Digest, GetMemPoolResult](s =>
|
||||
implicit def mapDoubleSha256DigestReadsPreV19: Reads[
|
||||
Map[DoubleSha256Digest, GetMemPoolResultPreV19]] =
|
||||
Reads.mapReads[DoubleSha256Digest, GetMemPoolResultPreV19](s =>
|
||||
JsSuccess(DoubleSha256Digest.fromHex(s)))
|
||||
|
||||
implicit def mapDoubleSha256DigestBEReads: Reads[
|
||||
Map[DoubleSha256DigestBE, GetMemPoolResult]] =
|
||||
Reads.mapReads[DoubleSha256DigestBE, GetMemPoolResult](s =>
|
||||
implicit def mapDoubleSha256DigestReadsPostV19: Reads[
|
||||
Map[DoubleSha256Digest, GetMemPoolResultPostV19]] =
|
||||
Reads.mapReads[DoubleSha256Digest, GetMemPoolResultPostV19](s =>
|
||||
JsSuccess(DoubleSha256Digest.fromHex(s)))
|
||||
|
||||
implicit def mapDoubleSha256DigestBEReadsPreV19: Reads[
|
||||
Map[DoubleSha256DigestBE, GetMemPoolResultPreV19]] =
|
||||
Reads.mapReads[DoubleSha256DigestBE, GetMemPoolResultPreV19](s =>
|
||||
JsSuccess(DoubleSha256DigestBE.fromHex(s)))
|
||||
|
||||
implicit def mapDoubleSha256DigestBEReadsPostV19: Reads[
|
||||
Map[DoubleSha256DigestBE, GetMemPoolResultPostV19]] =
|
||||
Reads.mapReads[DoubleSha256DigestBE, GetMemPoolResultPostV19](s =>
|
||||
JsSuccess(DoubleSha256DigestBE.fromHex(s)))
|
||||
|
||||
implicit def mapAddressesByLabelReads: Reads[
|
||||
|
@ -173,6 +173,19 @@ object ServiceIdentifier extends Factory[ServiceIdentifier] {
|
||||
def fromBytes(bytes: ByteVector): ServiceIdentifier =
|
||||
RawServiceIdentifierSerializer.read(bytes)
|
||||
|
||||
def fromString(string: String): ServiceIdentifier = string match {
|
||||
case "NETWORK" => NODE_NETWORK
|
||||
case "NETWORK_LIMITED" => NODE_NETWORK_LIMITED
|
||||
case "WITNESS" => NODE_WITNESS
|
||||
case "BLOOM" => NODE_BLOOM
|
||||
case "GETUTXO" => NODE_GET_UTXO
|
||||
case "COMPACT_FILTERS" => NODE_COMPACT_FILTERS
|
||||
case "XTHIN" => NODE_XTHIN
|
||||
case _: String =>
|
||||
throw new IllegalArgumentException(
|
||||
s""""$string" does not represent a ServiceIdentifier""")
|
||||
}
|
||||
|
||||
def apply(num: BigInt): ServiceIdentifier = ServiceIdentifier(UInt64(num))
|
||||
|
||||
def apply(uInt64: UInt64): ServiceIdentifier = ServiceIdentifierImpl(uInt64)
|
||||
|
@ -16,6 +16,7 @@ import org.bitcoins.node.networking.peer.{
|
||||
PeerMessageReceiverState,
|
||||
PeerMessageSender
|
||||
}
|
||||
import org.bitcoins.rpc.client.common.BitcoindVersion.V18
|
||||
import org.bitcoins.rpc.client.common.{BitcoindRpcClient, BitcoindVersion}
|
||||
import org.bitcoins.server.BitcoinSAppConfig
|
||||
import org.bitcoins.server.BitcoinSAppConfig._
|
||||
@ -110,8 +111,9 @@ trait NodeUnitTest extends BitcoinSFixture {
|
||||
|
||||
makeDependentFixture(
|
||||
build = () =>
|
||||
NodeUnitTest.createSpvNodeFundedWalletBitcoind(callbacks)(system,
|
||||
appConfig),
|
||||
NodeUnitTest.createSpvNodeFundedWalletBitcoind(callbacks, Option(V18))(
|
||||
system, // Force V18 because Spv is disabled on versions after
|
||||
appConfig),
|
||||
destroy = NodeUnitTest.destroyNodeFundedWalletBitcoind(
|
||||
_: NodeFundedWalletBitcoind)(system, appConfig)
|
||||
)(test)
|
||||
|
@ -40,6 +40,7 @@ import org.bitcoins.rpc.client.common.{
|
||||
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.config.{
|
||||
BitcoindAuthCredentials,
|
||||
BitcoindConfig,
|
||||
@ -115,6 +116,7 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger {
|
||||
|port=${uri.getPort}
|
||||
|debug=1
|
||||
|walletbroadcast=1
|
||||
|peerbloomfilters=1
|
||||
|txindex=${if (pruneMode) 0 else 1 /* pruning and txindex are not compatible */}
|
||||
|zmqpubhashtx=tcp://127.0.0.1:$zmqPort
|
||||
|zmqpubhashblock=tcp://127.0.0.1:$zmqPort
|
||||
@ -180,7 +182,7 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger {
|
||||
def getBinary(version: BitcoindVersion): File = version match {
|
||||
// default to newest version
|
||||
case Unknown => getBinary(BitcoindVersion.newest)
|
||||
case known @ (Experimental | V16 | V17 | V18) =>
|
||||
case known @ (Experimental | V16 | V17 | V18 | V19) =>
|
||||
val fileList = Files
|
||||
.list(binaryDirectory)
|
||||
.iterator()
|
||||
@ -223,12 +225,14 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger {
|
||||
versionOpt: Option[BitcoindVersion] = None): BitcoindInstance = {
|
||||
val uri = new URI("http://localhost:" + port)
|
||||
val rpcUri = new URI("http://localhost:" + rpcPort)
|
||||
val configFile = writtenConfig(
|
||||
uri,
|
||||
rpcUri,
|
||||
zmqPort,
|
||||
pruneMode,
|
||||
blockFilterIndex = versionOpt.contains(BitcoindVersion.Experimental))
|
||||
val hasNeutrinoSupport = versionOpt.contains(BitcoindVersion.V19) || versionOpt
|
||||
.contains(BitcoindVersion.Experimental)
|
||||
val configFile =
|
||||
writtenConfig(uri,
|
||||
rpcUri,
|
||||
zmqPort,
|
||||
pruneMode,
|
||||
blockFilterIndex = hasNeutrinoSupport)
|
||||
val conf = BitcoindConfig(configFile)
|
||||
val auth = BitcoindAuthCredentials.fromConfig(conf)
|
||||
val binary: File = versionOpt match {
|
||||
@ -292,6 +296,18 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger {
|
||||
pruneMode = pruneMode,
|
||||
versionOpt = Some(BitcoindVersion.V18))
|
||||
|
||||
def v19Instance(
|
||||
port: Int = RpcUtil.randomPort,
|
||||
rpcPort: Int = RpcUtil.randomPort,
|
||||
zmqPort: Int = RpcUtil.randomPort,
|
||||
pruneMode: Boolean = false
|
||||
): BitcoindInstance =
|
||||
instance(port = port,
|
||||
rpcPort = rpcPort,
|
||||
zmqPort = zmqPort,
|
||||
pruneMode = pruneMode,
|
||||
versionOpt = Some(BitcoindVersion.V19))
|
||||
|
||||
def vExperimentalInstance(
|
||||
port: Int = RpcUtil.randomPort,
|
||||
rpcPort: Int = RpcUtil.randomPort,
|
||||
@ -595,8 +611,11 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger {
|
||||
case BitcoindVersion.V18 =>
|
||||
BitcoindV18RpcClient.withActorSystem(
|
||||
BitcoindRpcTestUtil.v18Instance())
|
||||
case BitcoindVersion.V19 =>
|
||||
BitcoindV19RpcClient.withActorSystem(
|
||||
BitcoindRpcTestUtil.v19Instance())
|
||||
case BitcoindVersion.Experimental =>
|
||||
BitcoindV18RpcClient.withActorSystem(
|
||||
BitcoindV19RpcClient.withActorSystem(
|
||||
BitcoindRpcTestUtil.vExperimentalInstance())
|
||||
}
|
||||
|
||||
@ -672,6 +691,15 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger {
|
||||
(BitcoindV18RpcClient, BitcoindV18RpcClient)] =
|
||||
createNodePairInternal(BitcoindVersion.V18, clientAccum)
|
||||
|
||||
/**
|
||||
* Returns a pair of [[org.bitcoins.rpc.client.v19.BitcoindV19RpcClient BitcoindV19RpcClient]]
|
||||
* that are connected with some blocks in the chain
|
||||
*/
|
||||
def createNodePairV19(clientAccum: RpcClientAccum = Vector.newBuilder)(
|
||||
implicit system: ActorSystem): Future[
|
||||
(BitcoindV19RpcClient, BitcoindV19RpcClient)] =
|
||||
createNodePairInternal(BitcoindVersion.V19, clientAccum)
|
||||
|
||||
/**
|
||||
* Returns a triple of [[org.bitcoins.rpc.client.common.BitcoindRpcClient BitcoindRpcClient]]
|
||||
* that are connected with some blocks in the chain
|
||||
@ -718,6 +746,13 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger {
|
||||
createNodeTripleInternal(BitcoindVersion.V18, clientAccum)
|
||||
}
|
||||
|
||||
def createNodeTripleV19(
|
||||
clientAccum: RpcClientAccum = Vector.newBuilder
|
||||
)(implicit system: ActorSystem): Future[
|
||||
(BitcoindV19RpcClient, BitcoindV19RpcClient, BitcoindV19RpcClient)] = {
|
||||
createNodeTripleInternal(BitcoindVersion.V19, clientAccum)
|
||||
}
|
||||
|
||||
def createRawCoinbaseTransaction(
|
||||
sender: BitcoindRpcClient,
|
||||
receiver: BitcoindRpcClient,
|
||||
@ -769,17 +804,20 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger {
|
||||
val v16T = BitcoindV16RpcClient.fromUnknownVersion(unknown)
|
||||
val v17T = BitcoindV17RpcClient.fromUnknownVersion(unknown)
|
||||
val v18T = BitcoindV18RpcClient.fromUnknownVersion(unknown)
|
||||
(v16T, v17T, v18T) match {
|
||||
case (Failure(_), Failure(_), Failure(_)) =>
|
||||
val v19T = BitcoindV19RpcClient.fromUnknownVersion(unknown)
|
||||
(v16T, v17T, v18T, v19T) match {
|
||||
case (Failure(_), Failure(_), Failure(_), Failure(_)) =>
|
||||
throw new RuntimeException(
|
||||
"Could not figure out version of provided bitcoind RPC client!" +
|
||||
"This should not happen, managed to construct different versioned RPC clients from one single client")
|
||||
case (Success(v16), _, _) =>
|
||||
case (Success(v16), _, _, _) =>
|
||||
v16.signRawTransaction(transaction, utxoDeps)
|
||||
case (_, Success(v17), _) =>
|
||||
case (_, Success(v17), _, _) =>
|
||||
v17.signRawTransactionWithWallet(transaction, utxoDeps)
|
||||
case (_, _, Success(v18)) =>
|
||||
case (_, _, Success(v18), _) =>
|
||||
v18.signRawTransactionWithWallet(transaction, utxoDeps)
|
||||
case (_, _, _, Success(v19)) =>
|
||||
v19.signRawTransactionWithWallet(transaction, utxoDeps)
|
||||
}
|
||||
}
|
||||
|
||||
@ -820,8 +858,7 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger {
|
||||
addr <- sender.getNewAddress
|
||||
_ <- sender.generateToAddress(100, addr)
|
||||
// Can't spend coinbase until depth 100
|
||||
transactionHash <- sender.sendRawTransaction(signedtx.hex,
|
||||
allowHighFees = true)
|
||||
transactionHash <- sender.sendRawTransaction(signedtx.hex, maxfeerate = 0)
|
||||
transaction <- sender.getTransaction(transactionHash)
|
||||
} yield transaction
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user