diff --git a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/bitcoind/WalletResult.scala b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/bitcoind/WalletResult.scala index 30cc3e5a19..e6eb013b53 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/bitcoind/WalletResult.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/bitcoind/WalletResult.scala @@ -256,120 +256,6 @@ sealed trait AddressInfoResult extends WalletResult { def hdseedid: Option[RipeMd160Digest] } -case class AddressInfoResultPreV18( - address: BitcoinAddress, - scriptPubKey: ScriptPubKey, - ismine: Boolean, - iswatchonly: Boolean, - isscript: Boolean, - iswitness: Boolean, - iscompressed: Option[Boolean], - witness_version: Option[WitnessVersion], - witness_program: Option[String], - script: Option[ScriptType], - hex: Option[ScriptPubKey], - pubkeys: Option[Vector[ECPublicKey]], - sigsrequired: Option[Int], - pubkey: Option[ECPublicKey], - embedded: Option[EmbeddedResult], - label: String, - timestamp: Option[ZonedDateTime], - hdkeypath: Option[BIP32Path], - hdseedid: Option[RipeMd160Digest], - hdmasterkeyid: Option[RipeMd160Digest], - labels: Vector[LabelResult] -) extends AddressInfoResult - -// The split into two case classes is to deal with the 22 param limit for case classes -case class AddressInfoResultPostV18( - address: BitcoinAddress, - scriptPubKey: ScriptPubKey, - isProps: AddressInfoResultPostV18.AddressInfoIsProps, - desc: String, - witness_version: Option[WitnessVersion], - witness_program: Option[String], - script: Option[ScriptType], - hex: Option[ScriptPubKey], - pubkeys: Option[Vector[ECPublicKey]], - sigsrequired: Option[Int], - pubkey: Option[ECPublicKey], - embedded: Option[EmbeddedResult], - label: String, - ischange: Boolean, - timestamp: Option[ZonedDateTime], - hdkeypath: Option[BIP32Path], - hdseedid: Option[RipeMd160Digest], - hdmasterfingerprint: Option[String], - labels: Vector[LabelResult] -) extends AddressInfoResult { - override def ismine: Boolean = isProps.ismine - def solvable: Boolean = isProps.solvable - override def iswatchonly: Boolean = isProps.iswatchonly - override def isscript: Boolean = isProps.isscript - override def iswitness: Boolean = isProps.iswitness - override def iscompressed: Option[Boolean] = isProps.iscompressed -} - -object AddressInfoResultPostV18 { - - case class AddressInfoIsProps( - ismine: Boolean, - solvable: Boolean, - iswatchonly: Boolean, - isscript: Boolean, - iswitness: Boolean, - iscompressed: Option[Boolean] - ) - - case class AddressInfoResultPostV18WithoutIsProps( - address: BitcoinAddress, - scriptPubKey: ScriptPubKey, - desc: String, - witness_version: Option[WitnessVersion], - witness_program: Option[String], - script: Option[ScriptType], - hex: Option[ScriptPubKey], - pubkeys: Option[Vector[ECPublicKey]], - sigsrequired: Option[Int], - pubkey: Option[ECPublicKey], - embedded: Option[EmbeddedResult], - label: String, - ischange: Boolean, - timestamp: Option[ZonedDateTime], - hdkeypath: Option[BIP32Path], - hdseedid: Option[RipeMd160Digest], - hdmasterfingerprint: Option[String], - labels: Vector[LabelResult] - ) - - def apply( - info: AddressInfoResultPostV18WithoutIsProps, - isProps: AddressInfoIsProps - ): AddressInfoResultPostV18 = { - AddressInfoResultPostV18( - address = info.address, - scriptPubKey = info.scriptPubKey, - isProps = isProps, - desc = info.desc, - witness_version = info.witness_version, - witness_program = info.witness_program, - script = info.script, - hex = info.hex, - pubkeys = info.pubkeys, - sigsrequired = info.sigsrequired, - pubkey = info.pubkey, - embedded = info.embedded, - label = info.label, - ischange = info.ischange, - timestamp = info.timestamp, - hdkeypath = info.hdkeypath, - hdseedid = info.hdseedid, - hdmasterfingerprint = info.hdmasterfingerprint, - labels = info.labels - ) - } -} - case class AddressInfoResultPostV21( address: BitcoinAddress, scriptPubKey: ScriptPubKey, diff --git a/app-commons/src/main/scala/org/bitcoins/commons/serializers/JsonSerializers.scala b/app-commons/src/main/scala/org/bitcoins/commons/serializers/JsonSerializers.scala index fcf6f28e44..ea4064686e 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/serializers/JsonSerializers.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/serializers/JsonSerializers.scala @@ -515,27 +515,6 @@ object JsonSerializers { implicit val embeddedResultReads: Reads[EmbeddedResult] = Json.reads[EmbeddedResult] - implicit val addressInfoResultPreV18Reads: Reads[AddressInfoResultPreV18] = - Json.reads[AddressInfoResultPreV18] - - implicit val addressInfoResultPostV18Reads - : Reads[AddressInfoResultPostV18] = { - Reads[AddressInfoResultPostV18] { json => - for { - isProps <- - Json.reads[AddressInfoResultPostV18.AddressInfoIsProps].reads(json) - infoWithoutProps <- - Json - .reads[ - AddressInfoResultPostV18.AddressInfoResultPostV18WithoutIsProps - ] - .reads(json) - } yield { - AddressInfoResultPostV18(infoWithoutProps, isProps) - } - } - } - implicit val addressInfoResultPostV21Reads : Reads[AddressInfoResultPostV21] = { Reads[AddressInfoResultPostV21] { json => diff --git a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/BitcoindVersionTest.scala b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/BitcoindVersionTest.scala index e283553e19..a054115859 100644 --- a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/BitcoindVersionTest.scala +++ b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/BitcoindVersionTest.scala @@ -6,9 +6,9 @@ import org.bitcoins.testkit.util.BitcoindRpcTest class BitcoindVersionTest extends BitcoindRpcTest { behavior of "BitcoindVersion" - it should "return version 24" in { - val version = BitcoindVersion.fromNetworkVersion(240100) - assert(version.equals(BitcoindVersion.V24)) + it should "return version 25" in { + val version = BitcoindVersion.fromNetworkVersion(250100) + assert(version.equals(BitcoindVersion.V25)) } } diff --git a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/MempoolRpcTest.scala b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/MempoolRpcTest.scala index b0bef4e04a..707dc23c9b 100644 --- a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/MempoolRpcTest.scala +++ b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/MempoolRpcTest.scala @@ -2,6 +2,7 @@ package org.bitcoins.rpc.common import org.bitcoins.core.currency.Bitcoins import org.bitcoins.core.number.UInt32 +import org.bitcoins.core.protocol.BitcoinAddress import org.bitcoins.core.protocol.script.ScriptSignature import org.bitcoins.core.protocol.transaction.{ TransactionInput, @@ -193,4 +194,15 @@ class MempoolRpcTest extends BitcoindFixturesCachedPairNewest { _ <- client.saveMemPool() } yield assert(regTest.list().contains("mempool.dat")) } + + it should "get tx spending prev out" in { nodePair => + val client = nodePair.node1 + val junkAddress: BitcoinAddress = + BitcoinAddress("2NFyxovf6MyxfHqtVjstGzs6HeLqv92Nq4U") + for { + txid <- client.sendToAddress(junkAddress, Bitcoins.one) + tx <- client.getRawTransaction(txid).map(_.hex) + spending <- client.getTxSpendingPrevOut(tx.inputs.head.previousOutput) + } yield assert(spending.spendingtxid.contains(txid)) + } } diff --git a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/MessageRpcTest.scala b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/MessageRpcTest.scala deleted file mode 100644 index fa1b1e69a7..0000000000 --- a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/MessageRpcTest.scala +++ /dev/null @@ -1,42 +0,0 @@ -package org.bitcoins.rpc.common - -import org.bitcoins.commons.jsonmodels.bitcoind.RpcOpts.AddressType -import org.bitcoins.core.protocol.P2PKHAddress -import org.bitcoins.crypto.ECPrivateKey -import org.bitcoins.testkit.rpc.BitcoindFixturesCachedPairNewest - -class MessageRpcTest extends BitcoindFixturesCachedPairNewest { - - behavior of "MessageRpc" - - it should "be able to sign a message and verify that signature" in { - nodePair => - val client = nodePair.node1 - val message = "Never gonna give you up\nNever gonna let you down\n..." - for { - address <- client.getNewAddress(addressType = AddressType.Legacy) - signature <- - client.signMessage(address.asInstanceOf[P2PKHAddress], message) - validity <- - client - .verifyMessage(address.asInstanceOf[P2PKHAddress], - signature, - message) - } yield assert(validity) - } - - it should "be able to sign a message with a private key and verify that signature" in { - nodePair => - val message = "Never gonna give you up\nNever gonna let you down\n..." - val privKey = ECPrivateKey.freshPrivateKey - val address = P2PKHAddress(privKey.publicKey, networkParam) - val client = nodePair.node1 - for { - signature <- client.signMessageWithPrivKey( - privKey.toPrivateKeyBytes(), - message - ) - validity <- client.verifyMessage(address, signature, message) - } yield assert(validity) - } -} diff --git a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/MiningRpcTest.scala b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/MiningRpcTest.scala index f43b984e12..c206baa64b 100644 --- a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/MiningRpcTest.scala +++ b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/MiningRpcTest.scala @@ -4,11 +4,14 @@ import org.bitcoins.commons.jsonmodels.bitcoind.{ GetBlockWithTransactionsResultV22, RpcOpts } +import org.bitcoins.core.api.chain.db.BlockHeaderDbHelper import org.bitcoins.core.currency.Bitcoins import org.bitcoins.core.number._ +import org.bitcoins.core.protocol.blockchain.RegTestNetChainParams import org.bitcoins.core.protocol.script.ScriptSignature import org.bitcoins.core.protocol.transaction._ import org.bitcoins.crypto.DoubleSha256DigestBE +import org.bitcoins.testkit.chain.BlockHeaderHelper import org.bitcoins.testkit.rpc.{ BitcoindFixturesCachedPairNewest, BitcoindRpcTestUtil @@ -135,4 +138,13 @@ class MiningRpcTest extends BitcoindFixturesCachedPairNewest { hps <- client.getNetworkHashPS() } yield assert(hps > 0) } + + it should "successfully submit a header" in { case nodePair => + val client = nodePair.node1 + val genesisHeader = RegTestNetChainParams.genesisBlock.blockHeader + val genesisHeaderDb = + BlockHeaderDbHelper.fromBlockHeader(height = 1, BigInt(0), genesisHeader) + val nextHeader = BlockHeaderHelper.buildNextHeader(genesisHeaderDb) + client.submitHeader(nextHeader.blockHeader).map(_ => succeed) + } } diff --git a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/NodeRpcTest.scala b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/NodeRpcTest.scala index 70a7f53739..77335dadfd 100644 --- a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/NodeRpcTest.scala +++ b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/NodeRpcTest.scala @@ -70,4 +70,21 @@ class NodeRpcTest extends BitcoindFixturesFundedCachedNewest { assert(!helpHelp.isEmpty) } } + + it should "be able to get network info" in { freshClient => + for { + info <- freshClient.getNetworkInfo + } yield { + assert(info.networkactive) + assert(info.localrelay) + } + } + + it should "get node address given a null parameter" in { client => + val nodeF = client.getNodeAddresses() + + nodeF.map { result => + assert(result.isEmpty) + } + } } diff --git a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/UtilRpcTest.scala b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/UtilRpcTest.scala new file mode 100644 index 0000000000..3a266f77f1 --- /dev/null +++ b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/UtilRpcTest.scala @@ -0,0 +1,126 @@ +package org.bitcoins.rpc.common + +import org.bitcoins.asyncutil.AsyncUtil +import org.bitcoins.commons.jsonmodels.bitcoind.RpcOpts.AddressType +import org.bitcoins.core.protocol.{BitcoinAddress, P2PKHAddress} +import org.bitcoins.core.protocol.script.descriptor.Descriptor +import org.bitcoins.crypto.ECPrivateKey +import org.bitcoins.rpc.client.common.BitcoindRpcClient +import org.bitcoins.testkit.rpc.BitcoindFixturesCachedPairNewest + +import scala.concurrent.Future + +class UtilRpcTest extends BitcoindFixturesCachedPairNewest { + + behavior of "UtilRpc" + + it should "be able to sign a message and verify that signature" in { + nodePair => + val client = nodePair.node1 + val message = "Never gonna give you up\nNever gonna let you down\n..." + for { + address <- client.getNewAddress(addressType = AddressType.Legacy) + signature <- + client.signMessage(address.asInstanceOf[P2PKHAddress], message) + validity <- + client + .verifyMessage(address.asInstanceOf[P2PKHAddress], + signature, + message) + } yield assert(validity) + } + + it should "be able to sign a message with a private key and verify that signature" in { + nodePair => + val message = "Never gonna give you up\nNever gonna let you down\n..." + val privKey = ECPrivateKey.freshPrivateKey + val address = P2PKHAddress(privKey.publicKey, networkParam) + val client = nodePair.node1 + for { + signature <- client.signMessageWithPrivKey( + privKey.toPrivateKeyBytes(), + message + ) + validity <- client.verifyMessage(address, signature, message) + } yield assert(validity) + } + + it should "get index info" in { nodePair => + val client = nodePair.node1 + + def indexSynced(client: BitcoindRpcClient): Future[Boolean] = { + for { + blockCount <- client.getBlockCount() + indexes <- client.getIndexInfo + } yield { + indexes("txindex").best_block_height == blockCount && indexes( + "basic block filter index" + ).best_block_height == blockCount + } + } + for { + _ <- AsyncUtil.retryUntilSatisfiedF(() => indexSynced(client)) + indexes <- client.getIndexInfo + blockCount <- client.getBlockCount() + } yield { + val txIndexInfo = indexes("txindex") + assert(txIndexInfo.synced) + assert(txIndexInfo.best_block_height == blockCount) + + val blockFilterIndexInfo = indexes("basic block filter index") + assert(blockFilterIndexInfo.synced) + assert(blockFilterIndexInfo.best_block_height == blockCount) + } + } + + it should "return active rpc commands" in { nodePair => + val client = nodePair.node1 + val generatedF = + client.getNewAddress.flatMap(addr => client.generateToAddress(100, addr)) + val rpcinfoF = + generatedF.flatMap(_ => client.getRpcInfo()) + + rpcinfoF.map { result => + assert(result.active_commands.length == 1) + } + } + + it should "derive addresses from a descriptor" in { case nodePair => + val client = nodePair.node1 + val str0 = + "wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0)#t6wfjs64" + val descriptor0 = Descriptor.fromString(str0) + assert(descriptor0.toString == str0) + val addresses0F = + client.deriveAddresses(descriptor0, None).map(_.addresses) + val expected0 = + Vector("bcrt1qjqmxmkpmxt80xz4y3746zgt0q3u3ferr34acd5").map( + BitcoinAddress.fromString + ) + val assert0 = addresses0F.map { addresses => + assert(addresses == expected0) + } + + val str1 = + "wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)#kft60nuy" + + val descriptor1 = Descriptor.fromString(str1) + assert(descriptor1.toString == str1) + val addresses1F = + client.deriveAddresses(descriptor1, Some(Vector(0, 2))).map(_.addresses) + val expected1 = + Vector( + "bcrt1qjqmxmkpmxt80xz4y3746zgt0q3u3ferr34acd5", + "bcrt1qhku5rq7jz8ulufe2y6fkcpnlvpsta7rq4442dy", + "bcrt1qpgptk2gvshyl0s9lqshsmx932l9ccsv265tvaq" + ) + .map(BitcoinAddress.fromString) + + val assert1 = assert0.flatMap(_ => + addresses1F.map { addresses => + assert(addresses == expected1) + }) + + assert1 + } +} diff --git a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/WalletRpcTest.scala b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/WalletRpcTest.scala index d222e2bb7a..3c3707fec2 100644 --- a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/WalletRpcTest.scala +++ b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/WalletRpcTest.scala @@ -6,6 +6,7 @@ import org.bitcoins.commons.jsonmodels.bitcoind.RpcOpts.{ WalletFlag } import org.bitcoins.commons.jsonmodels.bitcoind.{ + AddressInfoResultPostV21, DecodeScriptResultV22, DescriptorsResult, GetWalletInfoResultPostV22 @@ -15,6 +16,7 @@ import org.bitcoins.core.currency.{Bitcoins, CurrencyUnit, Satoshis} import org.bitcoins.core.number.UInt32 import org.bitcoins.core.protocol.script._ import org.bitcoins.core.protocol.script.descriptor.{ + Descriptor, P2SHDescriptor, P2WPKHDescriptor } @@ -726,7 +728,7 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest { for { _ <- client.unloadWallet(BitcoindRpcClient.DEFAULT_WALLET_NAME) _ <- client.createWallet(walletName, descriptors = true) - _ <- client.importDescriptor(imp, Some(walletName)) + _ <- client.importDescriptor(imp, walletName) decoded <- client.decodeScript(p2wpkh) _ <- client.unloadWallet(walletName) _ <- client.loadWallet(BitcoindRpcClient.DEFAULT_WALLET_NAME) @@ -738,6 +740,96 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest { } } + it should "simulate a transaction" in { nodePair => + val client = nodePair.node1 + val junkAddress: BitcoinAddress = + BitcoinAddress("2NFyxovf6MyxfHqtVjstGzs6HeLqv92Nq4U") + for { + txid <- client.sendToAddress(junkAddress, Bitcoins.one) + tx <- client.getRawTransaction(txid).map(_.hex) + change <- client.simulateRawTransaction(tx) + } yield { + assert(change <= -Bitcoins.one) + } // 1 bitcoin + fees + } + + it should "be able to validate a bitcoin address" in { case nodePair => + val client = nodePair.node1 + for { + address <- client.getNewAddress + validation <- client.validateAddress(address) + } yield assert(validation.isvalid) + } + + it should "have extra address information" in { case nodePair => + val client = nodePair.node1 + for { + address <- client.getNewAddress + info <- client.getAddressInfo(address) + } yield { + info match { + case postV21Info: AddressInfoResultPostV21 => + assert(postV21Info.address == address) + } + } + } + + it should "analyze a descriptor" in { case nodePair => + val client = nodePair.node1 + val descriptor = + Descriptor.fromString( + "pk(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)#gn28ywm7" + ) + + val descriptorF = client.getDescriptorInfo(descriptor) + + descriptorF.map { result => + assert(result.descriptor == descriptor) + assert(result.isrange.==(false)) + assert(result.issolvable.==(true)) + assert(result.hasprivatekeys.==(false)) + } + } + + it must "importdescriptors" in { nodePair => + val client = nodePair.node1 + val str1 = + "wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)#kft60nuy" + val descriptor = Descriptor.fromString(str1) + val imp = DescriptorsResult( + desc = descriptor, + timestamp = Instant.now().getEpochSecond, + active = true, + internal = None, + range = Some(Vector(0, 2)), + next = None + ) + + val resultF = + client.importDescriptors(imports = Vector(imp)) + + for { + result <- resultF + _ = assert(result.forall(_.success)) + firstAddress <- client.getNewAddress + secondAddress <- client.getNewAddress + // check it by deriving addresses externally + deriveAddresses <- client + .deriveAddresses(descriptor, Some(Vector(0, 1))) + .map(_.addresses) + } yield { + assert(Vector(firstAddress, secondAddress) == deriveAddresses) + } + } + + it should "be able to get the address info for a given address" in { + case nodePair => + val client = nodePair.node1 + for { + addr <- client.getNewAddress + info <- client.getAddressInfo(addr) + } yield assert(info.address == addr) + } def startClient(client: BitcoindRpcClient): Future[Unit] = { BitcoindRpcTestUtil.startServers(Vector(client)) } diff --git a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/v24/BitcoindV24RpcClientTest.scala b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/v24/BitcoindV24RpcClientTest.scala deleted file mode 100644 index aef80049c2..0000000000 --- a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/v24/BitcoindV24RpcClientTest.scala +++ /dev/null @@ -1,410 +0,0 @@ -package org.bitcoins.rpc.v24 - -import org.bitcoins.asyncutil.AsyncUtil -import org.bitcoins.commons.jsonmodels.bitcoind.RpcOpts.{ - AddressType, - WalletFlag -} -import org.bitcoins.commons.jsonmodels.bitcoind._ -import org.bitcoins.core.api.chain.db.BlockHeaderDbHelper -import org.bitcoins.core.config.RegTest -import org.bitcoins.core.currency._ -import org.bitcoins.core.gcs.{BlockFilter, FilterType} -import org.bitcoins.core.protocol.{Bech32mAddress, BitcoinAddress} -import org.bitcoins.core.protocol.blockchain.RegTestNetChainParams -import org.bitcoins.core.protocol.script.descriptor.Descriptor -import org.bitcoins.core.psbt.PSBT -import org.bitcoins.crypto.ECPublicKey -import org.bitcoins.rpc.client.common.{BitcoindRpcClient, BitcoindVersion} -import org.bitcoins.rpc.client.v24.BitcoindV24RpcClient -import org.bitcoins.testkit.chain.BlockHeaderHelper -import org.bitcoins.testkit.rpc.{ - BitcoindFixturesFundedCachedV24, - BitcoindRpcTestUtil -} - -import java.io.File -import java.nio.file.Files -import java.time.Instant -import scala.concurrent.Future - -class BitcoindV24RpcClientTest extends BitcoindFixturesFundedCachedV24 { - - val junkAddress: BitcoinAddress = - BitcoinAddress("2NFyxovf6MyxfHqtVjstGzs6HeLqv92Nq4U") - - behavior of "BitcoindV24RpcClient" - - it should "get index info" in { client: BitcoindV24RpcClient => - def indexSynced(client: BitcoindRpcClient): Future[Boolean] = { - client.getIndexInfo.map { indexes => - indexes("txindex").best_block_height == 101 && indexes( - "basic block filter index" - ).best_block_height == 101 - } - } - for { - _ <- AsyncUtil.retryUntilSatisfiedF(() => indexSynced(client)) - indexes <- client.getIndexInfo - } yield { - val txIndexInfo = indexes("txindex") - assert(txIndexInfo.synced) - assert(txIndexInfo.best_block_height == 101) - - val blockFilterIndexInfo = indexes("basic block filter index") - assert(blockFilterIndexInfo.synced) - assert(blockFilterIndexInfo.best_block_height == 101) - } - } - - it should "be able to start a V24 bitcoind instance" in { - client: BitcoindV24RpcClient => - for { - v <- client.version - } yield assert(v == BitcoindVersion.V24) - } - - it should "be able to get network info" in { - freshClient: BitcoindV24RpcClient => - for { - info <- freshClient.getNetworkInfo - } yield { - assert(info.networkactive) - assert(info.localrelay) - } - } - - it should "generate a bech32m address" in { client: BitcoindV24RpcClient => - for { - address <- client.getNewAddress(addressType = AddressType.Bech32m) - } yield { - assert(address.isInstanceOf[Bech32mAddress]) - } - } - - it should "be able to validate a bitcoin address" in { case client => - for { - address <- client.getNewAddress - validation <- client.validateAddress(address) - } yield assert(validation.isvalid) - } - - it should "have extra address information" in { client => - for { - address <- client.getNewAddress - info <- client.getAddressInfo(address) - } yield { - info match { - case _: AddressInfoResultPreV18 | _: AddressInfoResultPostV18 => - fail("Was expecting AddressInfoResultPostV21") - case postV21Info: AddressInfoResultPostV21 => - assert(postV21Info.address == address) - } - } - } - - it should "return active rpc commands" in { client => - val generatedF = - client.getNewAddress.flatMap(addr => client.generateToAddress(100, addr)) - val rpcinfoF = - generatedF.flatMap(_ => client.getRpcInfo()) - - rpcinfoF.map { result => - assert(result.active_commands.length == 1) - } - } - - it should "analyze a descriptor" in { client => - val descriptor = - Descriptor.fromString( - "pk(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)#gn28ywm7" - ) - - val descriptorF = client.getDescriptorInfo(descriptor) - - descriptorF.map { result => - assert(result.descriptor == descriptor) - assert(result.isrange.==(false)) - assert(result.issolvable.==(true)) - assert(result.hasprivatekeys.==(false)) - } - } - - it should "get node address given a null parameter" in { client => - val nodeF = client.getNodeAddresses() - - nodeF.map { result => - assert(result.isEmpty) - } - } - - it should "successfully submit a header" in { client => - val genesisHeader = RegTestNetChainParams.genesisBlock.blockHeader - val genesisHeaderDb = - BlockHeaderDbHelper.fromBlockHeader(height = 1, BigInt(0), genesisHeader) - val nextHeader = BlockHeaderHelper.buildNextHeader(genesisHeaderDb) - client.submitHeader(nextHeader.blockHeader).map(_ => succeed) - } - - it should "simulate a transaction" in { client => - for { - txid <- client.sendToAddress(junkAddress, Bitcoins.one) - tx <- client.getRawTransaction(txid).map(_.hex) - change <- client.simulateRawTransaction(tx) - } yield assert(change <= -Bitcoins.one) // 1 bitcoin + fees - } - - it should "get tx spending prev out" in { client => - for { - txid <- client.sendToAddress(junkAddress, Bitcoins.one) - tx <- client.getRawTransaction(txid).map(_.hex) - spending <- client.getTxSpendingPrevOut(tx.inputs.head.previousOutput) - } yield assert(spending.spendingtxid.contains(txid)) - } - - it should "derive addresses from a descriptor" in { client => - val str0 = - "wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0)#t6wfjs64" - val descriptor0 = Descriptor.fromString(str0) - assert(descriptor0.toString == str0) - val addresses0F = - client.deriveAddresses(descriptor0, None).map(_.addresses) - val expected0 = - Vector("bcrt1qjqmxmkpmxt80xz4y3746zgt0q3u3ferr34acd5").map( - BitcoinAddress.fromString - ) - val assert0 = addresses0F.map { addresses => - assert(addresses == expected0) - } - - val str1 = - "wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)#kft60nuy" - - val descriptor1 = Descriptor.fromString(str1) - assert(descriptor1.toString == str1) - val addresses1F = - client.deriveAddresses(descriptor1, Some(Vector(0, 2))).map(_.addresses) - val expected1 = - Vector( - "bcrt1qjqmxmkpmxt80xz4y3746zgt0q3u3ferr34acd5", - "bcrt1qhku5rq7jz8ulufe2y6fkcpnlvpsta7rq4442dy", - "bcrt1qpgptk2gvshyl0s9lqshsmx932l9ccsv265tvaq" - ) - .map(BitcoinAddress.fromString) - - val assert1 = assert0.flatMap(_ => - addresses1F.map { addresses => - assert(addresses == expected1) - }) - - assert1 - } - - it must "importdescriptors" in { client => - val str1 = - "wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)#kft60nuy" - val descriptor = Descriptor.fromString(str1) - val imp = DescriptorsResult( - desc = descriptor, - timestamp = Instant.now().getEpochSecond, - active = true, - internal = None, - range = Some(Vector(0, 2)), - next = None - ) - - val resultF = - client.importDescriptors(imports = Vector(imp), walletNameOpt = None) - - for { - result <- resultF - _ = assert(result.forall(_.success)) - firstAddress <- client.getNewAddress - secondAddress <- client.getNewAddress - // check it by deriving addresses externally - deriveAddresses <- client - .deriveAddresses(descriptor, Some(Vector(0, 1))) - .map(_.addresses) - } yield { - assert(Vector(firstAddress, secondAddress) == deriveAddresses) - } - } - - it should "be able to get the address info for a given address" in { - client: BitcoindV24RpcClient => - for { - addr <- client.getNewAddress - info <- client.getAddressInfo(addr) - } yield assert(info.address == addr) - } - - it should "get a block filter given a block hash" in { - client: BitcoindV24RpcClient => - for { - blocks <- client.generate(1) - blockHashBE = blocks.head - blockFilter <- client.getBlockFilter(blockHashBE, FilterType.Basic) - block <- client.getBlockRaw(blockHashBE) - prevOuts = block.transactions - .filterNot(_.isCoinbase) - .flatMap(_.inputs.map(_.previousOutput)) - fundingOutputs <- Future.traverse(prevOuts) { outpoint => - client - .getTransaction(outpoint.txIdBE) - .map(_.hex.outputs(outpoint.idx)) - } - prevFilter <- client.getBlockFilter( - block.blockHeader.previousBlockHashBE, - FilterType.Basic - ) - } yield { - val pubKeys = fundingOutputs.map(_.scriptPubKey).toVector - val filter = BlockFilter(block, pubKeys) - assert(filter.hash == blockFilter.filter.hash) - assert( - blockFilter.header == filter - .getHeader(prevFilter.header.flip) - .hashBE - ) - } - } - - it should "be able to get the balances" in { client: BitcoindV24RpcClient => - for { - immatureBalance <- client.getBalances - _ <- client.generate(1) - newImmatureBalance <- client.getBalances - } yield { - val blockReward = 50 - assert(immatureBalance.mine.immature.toBigDecimal >= 0) - assert( - immatureBalance.mine.trusted.toBigDecimal + blockReward == newImmatureBalance.mine.trusted.toBigDecimal - ) - } - } - - it should "be able to get blockchain info" in { - client: BitcoindV24RpcClient => - for { - info <- client.getBlockChainInfo - bestHash <- client.getBestBlockHash() - } yield { - assert(info.isInstanceOf[GetBlockChainInfoResultPostV23]) - val postV23Info = info.asInstanceOf[GetBlockChainInfoResultPostV23] - assert(postV23Info.chain == RegTest) - assert(postV23Info.bestblockhash == bestHash) - } - } - - it should "be able to get a block with verbose transactions" in { - client: BitcoindRpcClient => - for { - blocks <- client.generate(2) - block <- client.getBlockWithTransactions(blocks(1)) - } yield { - assert(block.hash == blocks(1)) - assert(block.tx.length == 1) - val tx = block.tx.head - assert(tx.vout.head.n == 0) - } - } - - it should "be able to set the wallet flag 'avoid_reuse'" in { - client: BitcoindV24RpcClient => - for { - 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 { - client: BitcoindV24RpcClient => - for { - _ <- 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 { - client: BitcoindV24RpcClient => - val descriptor = - "pk(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)" - - val psbt = - PSBT.fromBase64( - "cHNidP8BACoCAAAAAAFAQg8AAAAAABepFG6Rty1Vk+fUOR4v9E6R6YXDFkHwhwAAAAAAAA==" - ) - - for { - result <- client.utxoUpdatePsbt(psbt, Seq(descriptor)) - } yield { - assert(result == psbt) - } - } - - it should "correct create multisig and get its descriptor" in { - client: BitcoindV24RpcClient => - val pubKey1 = ECPublicKey.freshPublicKey - val pubKey2 = ECPublicKey.freshPublicKey - - for { - multiSigResult <- client.createMultiSig( - 2, - Vector(pubKey1, pubKey2), - AddressType.Bech32 - ) - } yield { - // just validate we are able to receive a sane descriptor - // no need to check checksum - assert( - multiSigResult.descriptor.startsWith( - s"wsh(multi(2,${pubKey1.hex},${pubKey2.hex}))#" - ) - ) - } - } - - it should "correctly dump tx out set" in { client: BitcoindV24RpcClient => - for { - 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 { - client: BitcoindV24RpcClient => - // 2-of-2 multisig descriptor - val descriptor = - "sh(sortedmulti(2,023f720438186fbdfde0c0a403e770a0f32a2d198623a8a982c47b621f8b307640,03ed261094d609d5e02ba6553c2d91e4fd056006ce2fe64aace72b69cb5be3ab9c))#nj9wx7up" - val numBlocks = 10 - for { - hashes <- client.generateToDescriptor(numBlocks, descriptor) - } yield assert(hashes.size == numBlocks) - } - - it should "be able to get utxo info" in { client: BitcoindRpcClient => - for { - block <- BitcoindRpcTestUtil.getFirstBlock(client) - info1 <- client.getTxOut(block.tx.head.txid, 0) - } yield assert(info1.coinbase) - } - -} diff --git a/bitcoind-rpc/bitcoind-rpc.sbt b/bitcoind-rpc/bitcoind-rpc.sbt index 13e0bd0d80..40363012a9 100644 --- a/bitcoind-rpc/bitcoind-rpc.sbt +++ b/bitcoind-rpc/bitcoind-rpc.sbt @@ -23,7 +23,7 @@ TaskKeys.downloadBitcoind := { } val versions = - List("25.2","24.2") + List("25.2") logger.debug( s"(Maybe) downloading Bitcoin Core binaries for versions: ${versions.mkString(",")}") @@ -94,24 +94,18 @@ TaskKeys.downloadBitcoind := { val expectedHash = if (Properties.isLinux) Map( - "25.2" -> "8d8c387e597e0edfc256f0bbace1dac3ad1ebf4a3c06da3e2975fda333817dea", - "24.2" -> "7540d6e34c311e355af2fd76e5eee853b76c291978d6b5ebb555c7877e9de38d", + "25.2" -> "8d8c387e597e0edfc256f0bbace1dac3ad1ebf4a3c06da3e2975fda333817dea" ) else if (Properties.isMac) Map( "25.2" -> (if (System.getProperty("os.arch") == "aarch64") "f55b394eebaa11d4b717d68aad9f75b824aaf3a7841dac7c26b1ef3d6d2915f5" else - "e06ba379f6039ca99bc32d3e7974d420a31363498936f88aac7bab6f239de0f5"), - "24.2" -> (if (System.getProperty("os.arch") == "aarch64") - "ae6f5f0cb4079005c32695711ef78b26a26c4c547ceb593b3626059626530a5d" - else - "b1b21455c339b2daf0998bfad17d0741d967c3c81db040bb5f73234168526d29") + "e06ba379f6039ca99bc32d3e7974d420a31363498936f88aac7bab6f239de0f5") ) else if (Properties.isWin) Map( - "25.2" -> "c2ac84f55ee879caefd4414868d318a741c52a7286da190bf7233d86a2ffca69", - "24.2" -> "544436bc9d5ce017e679bbccfe8a4928fbc840b414ee0240db8c3523ba54340a", + "25.2" -> "c2ac84f55ee879caefd4414868d318a741c52a7286da190bf7233d86a2ffca69" ) else sys.error(s"Unsupported OS: ${Properties.osName}") diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/BitcoindRpcClient.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/BitcoindRpcClient.scala index b83cdd92d7..f39bdea689 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/BitcoindRpcClient.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/BitcoindRpcClient.scala @@ -16,7 +16,6 @@ import org.bitcoins.core.wallet.fee.FeeUnit import org.bitcoins.crypto.{DoubleSha256DigestBE, StringFactory} import org.bitcoins.rpc.client.v18.V18AssortedRpc import org.bitcoins.rpc.client.v20.{V20AssortedRpc, V20MultisigRpc} -import org.bitcoins.rpc.client.v24.BitcoindV24RpcClient import org.bitcoins.rpc.client.v25.BitcoindV25RpcClient import org.bitcoins.rpc.config._ @@ -344,7 +343,6 @@ object BitcoindRpcClient { system: ActorSystem ): BitcoindRpcClient = { val bitcoind = version match { - case BitcoindVersion.V24 => BitcoindV24RpcClient.withActorSystem(instance) case BitcoindVersion.V25 => BitcoindV25RpcClient.withActorSystem(instance) case BitcoindVersion.Unknown => sys.error( @@ -372,14 +370,10 @@ object BitcoindVersion val newest: BitcoindVersion = V25 val standard: Vector[BitcoindVersion] = - Vector(V25, V24) + Vector(V25) val known: Vector[BitcoindVersion] = standard - case object V24 extends BitcoindVersion { - override def toString: String = "v24" - } - case object V25 extends BitcoindVersion { override def toString: String = "v25" } @@ -402,7 +396,7 @@ object BitcoindVersion def fromNetworkVersion(int: Int): BitcoindVersion = { // need to translate the int 210100 (as an example) to a BitcoindVersion int.toString.substring(0, 2) match { - case "24" => V24 + case "25" => V25 case _ => logger.warn( s"Unsupported Bitcoin Core version: $int. The latest supported version is ${BitcoindVersion.newest}" diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/DescriptorRpc.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/DescriptorRpc.scala index 121ad22de9..fb9d287b6e 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/DescriptorRpc.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/DescriptorRpc.scala @@ -49,20 +49,20 @@ trait DescriptorRpc { */ def importDescriptors( imports: Vector[DescriptorsResult], - walletNameOpt: Option[String] + walletName: String = BitcoindRpcClient.DEFAULT_WALLET_NAME ): Future[Vector[ImportDescriptorResult]] = { bitcoindCall[Vector[ImportDescriptorResult]]( "importdescriptors", List(Json.toJson(imports)), - uriExtensionOpt = walletNameOpt.map(walletExtension) + uriExtensionOpt = Some(walletExtension(walletName)) ) } def importDescriptor( imp: DescriptorsResult, - walletNameOpt: Option[String] + walletName: String = BitcoindRpcClient.DEFAULT_WALLET_NAME ): Future[ImportDescriptorResult] = { - importDescriptors(Vector(imp), walletNameOpt).map(_.head) + importDescriptors(Vector(imp), walletName).map(_.head) } def listDescriptors(): Future[ListDescriptorsResult] = { diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/MempoolRpc.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/MempoolRpc.scala index 75c1ce9b62..ff65fa2294 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/MempoolRpc.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/MempoolRpc.scala @@ -3,10 +3,10 @@ package org.bitcoins.rpc.client.common import org.bitcoins.commons.jsonmodels.bitcoind._ import org.bitcoins.commons.serializers.JsonReaders._ import org.bitcoins.commons.serializers.JsonSerializers._ -import org.bitcoins.core.protocol.transaction.Transaction +import org.bitcoins.core.protocol.transaction.{Transaction, TransactionOutPoint} import org.bitcoins.crypto.{DoubleSha256Digest, DoubleSha256DigestBE} import org.bitcoins.rpc.BitcoindException -import play.api.libs.json.{JsBoolean, JsString, Json} +import play.api.libs.json.{JsArray, JsBoolean, JsString, Json} import scala.concurrent.Future @@ -138,4 +138,23 @@ trait MempoolRpc { self: Client => List(Json.toJson(transaction), Json.toJson(maxFeeRate)) ) } + + def getTxSpendingPrevOut( + prevout: TransactionOutPoint + ): Future[GetTxSpendingPrevOutResult] = { + getTxSpendingPrevOut(Vector(prevout)).map(_.head) + } + + def getTxSpendingPrevOut( + prevouts: Vector[TransactionOutPoint] + ): Future[Vector[GetTxSpendingPrevOutResult]] = { + val json = JsArray(prevouts.map { prev => + Json.obj("txid" -> prev.txIdBE.hex, "vout" -> prev.vout.toLong) + }) + + bitcoindCall[Vector[GetTxSpendingPrevOutResult]]( + "gettxspendingprevout", + List(json) + ) + } } diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/UtilRpc.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/UtilRpc.scala index e937fa55b6..b0a48219e5 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/UtilRpc.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/UtilRpc.scala @@ -24,7 +24,7 @@ trait UtilRpc { self: Client => } def decodeScript(script: ScriptPubKey): Future[DecodeScriptResult] = { - self.version.flatMap { case V25 | V24 | Unknown => + self.version.flatMap { case V25 | Unknown => bitcoindCall[DecodeScriptResultV22]( "decodescript", List(Json.toJson(script)) @@ -34,18 +34,17 @@ trait UtilRpc { self: Client => } def getIndexInfo: Future[Map[String, IndexInfoResult]] = { - version.flatMap { case V25 | V24 | Unknown => + version.flatMap { case V25 | Unknown => bitcoindCall[Map[String, IndexInfoResult]]("getindexinfo") } } def getIndexInfo(indexName: String): Future[IndexInfoResult] = { - version.flatMap { case V25 | V24 | Unknown => + version.flatMap { case V25 | Unknown => bitcoindCall[Map[String, IndexInfoResult]]( "getindexinfo", List(JsString(indexName)) ).map(_.head._2) } - } } diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/WalletRpc.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/WalletRpc.scala index dd7478591e..77a51b4e71 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/WalletRpc.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/WalletRpc.scala @@ -160,13 +160,11 @@ trait WalletRpc { self: Client => def getWalletInfo( walletName: String ): Future[GetWalletInfoResult] = { - self.version.flatMap { - case BitcoindVersion.V25 | BitcoindVersion.V24 | - BitcoindVersion.Unknown => - bitcoindCall[GetWalletInfoResultPostV22]( - "getwalletinfo", - uriExtensionOpt = Some(walletExtension(walletName)) - ) + self.version.flatMap { case BitcoindVersion.V25 | BitcoindVersion.Unknown => + bitcoindCall[GetWalletInfoResultPostV22]( + "getwalletinfo", + uriExtensionOpt = Some(walletExtension(walletName)) + ) } } @@ -294,7 +292,7 @@ trait WalletRpc { self: Client => } def getBalances: Future[GetBalancesResult] = { - bitcoindCall[GetBalancesResult]("getbalances") + getBalances(BitcoindRpcClient.DEFAULT_WALLET_NAME) } def getBalances(walletName: String): Future[GetBalancesResult] = { @@ -383,7 +381,7 @@ trait WalletRpc { self: Client => descriptors: Boolean = false ): Future[CreateWalletResult] = self.version.flatMap { - case V25 | V24 => + case V25 => bitcoindCall[CreateWalletResult]( "createwallet", List( @@ -412,19 +410,12 @@ trait WalletRpc { self: Client => address: BitcoinAddress, walletName: String = DEFAULT_WALLET ): Future[AddressInfoResult] = { - self.version.flatMap { - case Unknown => - bitcoindCall[AddressInfoResultPostV18]( - "getaddressinfo", - List(JsString(address.value)), - uriExtensionOpt = Some(walletExtension(walletName)) - ) - case V25 | V24 => - bitcoindCall[AddressInfoResultPostV21]( - "getaddressinfo", - List(JsString(address.value)), - uriExtensionOpt = Some(walletExtension(walletName)) - ) + self.version.flatMap { case V25 | Unknown => + bitcoindCall[AddressInfoResultPostV21]( + "getaddressinfo", + List(JsString(address.value)), + uriExtensionOpt = Some(walletExtension(walletName)) + ) } } @@ -551,4 +542,27 @@ trait WalletRpc { self: Client => Json.toJson(sigHash) ) ) + + def simulateRawTransaction( + tx: Transaction, + includeWatchOnly: Boolean = true, + walletName: String = BitcoindRpcClient.DEFAULT_WALLET_NAME + ): Future[CurrencyUnit] = { + simulateRawTransactions(Vector(tx), includeWatchOnly, walletName) + } + + def simulateRawTransactions( + txs: Vector[Transaction], + includeWatchOnly: Boolean = true, + walletName: String = BitcoindRpcClient.DEFAULT_WALLET_NAME + ): Future[CurrencyUnit] = { + val txsJson = JsArray(txs.map(tx => JsString(tx.hex))) + val options = Json.obj("include_watchonly" -> includeWatchOnly) + + bitcoindCall[SimulateRawTransactionResult]( + "simulaterawtransaction", + List(txsJson, options), + uriExtensionOpt = Some(walletExtension(walletName)) + ).map(_.balance_change) + } } diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v24/BitcoindV24RpcClient.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v24/BitcoindV24RpcClient.scala deleted file mode 100644 index 325ae49ae5..0000000000 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v24/BitcoindV24RpcClient.scala +++ /dev/null @@ -1,97 +0,0 @@ -package org.bitcoins.rpc.client.v24 - -import org.apache.pekko.actor.ActorSystem -import org.bitcoins.commons.jsonmodels.bitcoind.{ - GetTxSpendingPrevOutResult, - SimulateRawTransactionResult -} -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.config.BitcoindInstance -import play.api.libs.json._ - -import scala.concurrent.Future -import scala.util.Try - -/** Class for creating a BitcoindV24 instance that can access RPCs - */ -class BitcoindV24RpcClient(override val instance: BitcoindInstance)(implicit - actorSystem: ActorSystem -) extends BitcoindRpcClient(instance) { - - override lazy val version: Future[BitcoindVersion] = - Future.successful(BitcoindVersion.V24) - - def getTxSpendingPrevOut( - prevout: TransactionOutPoint - ): Future[GetTxSpendingPrevOutResult] = { - getTxSpendingPrevOut(Vector(prevout)).map(_.head) - } - - def getTxSpendingPrevOut( - prevouts: Vector[TransactionOutPoint] - ): Future[Vector[GetTxSpendingPrevOutResult]] = { - val json = JsArray(prevouts.map { prev => - Json.obj("txid" -> prev.txIdBE.hex, "vout" -> prev.vout.toLong) - }) - - bitcoindCall[Vector[GetTxSpendingPrevOutResult]]( - "gettxspendingprevout", - List(json) - ) - } - - def simulateRawTransaction( - tx: Transaction, - includeWatchOnly: Boolean = true - ): Future[CurrencyUnit] = { - simulateRawTransactions(Vector(tx), includeWatchOnly) - } - - def simulateRawTransactions( - txs: Vector[Transaction], - includeWatchOnly: Boolean = true - ): Future[CurrencyUnit] = { - val txsJson = JsArray(txs.map(tx => JsString(tx.hex))) - val options = Json.obj("include_watchonly" -> includeWatchOnly) - - bitcoindCall[SimulateRawTransactionResult]( - "simulaterawtransaction", - List(txsJson, options) - ).map(_.balance_change) - } -} - -object BitcoindV24RpcClient { - - /** 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): BitcoindV24RpcClient = { - implicit val system: ActorSystem = - 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 - ): BitcoindV24RpcClient = - new BitcoindV24RpcClient(instance)(system) - - def fromUnknownVersion( - rpcClient: BitcoindRpcClient - ): Try[BitcoindV24RpcClient] = - Try { - new BitcoindV24RpcClient(rpcClient.instance)(rpcClient.system) - } - -} diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindInstance.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindInstance.scala index cbd8069458..b99ab2a258 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindInstance.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindInstance.scala @@ -59,9 +59,6 @@ sealed trait BitcoindInstanceLocal extends BitcoindInstance { .last foundVersion match { - case _: String - if foundVersion.startsWith(BitcoindVersion.V24.toString) => - BitcoindVersion.V24 case _: String if foundVersion.startsWith(BitcoindVersion.V25.toString) => BitcoindVersion.V25 diff --git a/eclair-rpc/src/main/scala/org/bitcoins/eclair/rpc/client/EclairRpcClient.scala b/eclair-rpc/src/main/scala/org/bitcoins/eclair/rpc/client/EclairRpcClient.scala index 57d5842a66..49b9ff1108 100644 --- a/eclair-rpc/src/main/scala/org/bitcoins/eclair/rpc/client/EclairRpcClient.scala +++ b/eclair-rpc/src/main/scala/org/bitcoins/eclair/rpc/client/EclairRpcClient.scala @@ -1090,5 +1090,5 @@ object EclairRpcClient { * @see * https://github.com/ACINQ/eclair/releases/tag/v0.8.0 */ - val bitcoindV: BitcoindVersion = BitcoindVersion.V24 + val bitcoindV: BitcoindVersion = BitcoindVersion.V25 } diff --git a/testkit/src/main/scala/org/bitcoins/testkit/rpc/BitcoindFixtures.scala b/testkit/src/main/scala/org/bitcoins/testkit/rpc/BitcoindFixtures.scala index 7b2c72e726..44164ebec6 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/rpc/BitcoindFixtures.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/rpc/BitcoindFixtures.scala @@ -2,7 +2,6 @@ package org.bitcoins.testkit.rpc import org.bitcoins.commons.jsonmodels.bitcoind.RpcOpts.AddNodeArgument import org.bitcoins.rpc.client.common.{BitcoindRpcClient, BitcoindVersion} -import org.bitcoins.rpc.client.v24.BitcoindV24RpcClient import org.bitcoins.rpc.client.v25.BitcoindV25RpcClient import org.bitcoins.rpc.util.{NodePair, NodeTriple} import org.bitcoins.testkit.EmbeddedPg @@ -49,39 +48,6 @@ trait BitcoindFixturesFundedCached extends BitcoindFixtures { } } -trait BitcoindFixturesFundedCachedV24 - extends BitcoinSAsyncFixtureTest - with BitcoindFixturesFundedCached - with CachedBitcoindV24 { - override type FixtureParam = BitcoindV24RpcClient - - override def withFixture(test: OneArgAsyncTest): FutureOutcome = { - val f: Future[Outcome] = for { - bitcoind <- cachedBitcoindWithFundsF - futOutcome = withV24FundedBitcoindCached(test, bitcoind) - fut <- futOutcome.toFuture - } yield fut - new FutureOutcome(f) - } - - def withV24FundedBitcoindCached( - test: OneArgAsyncTest, - bitcoind: BitcoindV24RpcClient - ): FutureOutcome = { - makeDependentFixture[BitcoindV24RpcClient]( - () => Future.successful(bitcoind), - { _ => - Future.unit // don't want to destroy anything since it is cached - } - )(test) - } - - override def afterAll(): Unit = { - super[CachedBitcoindV24].afterAll() - super[BitcoinSAsyncFixtureTest].afterAll() - } -} - trait BitcoindFixturesFundedCachedNewest extends BitcoinSAsyncFixtureTest with BitcoindFixturesFundedCached diff --git a/testkit/src/main/scala/org/bitcoins/testkit/rpc/BitcoindRpcTestUtil.scala b/testkit/src/main/scala/org/bitcoins/testkit/rpc/BitcoindRpcTestUtil.scala index b0edf51a45..b2b19e4d33 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/rpc/BitcoindRpcTestUtil.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/rpc/BitcoindRpcTestUtil.scala @@ -30,7 +30,6 @@ import org.bitcoins.crypto.{ import org.bitcoins.rpc.BitcoindException import org.bitcoins.rpc.client.common.BitcoindVersion._ import org.bitcoins.rpc.client.common.{BitcoindRpcClient, BitcoindVersion} -import org.bitcoins.rpc.client.v24.BitcoindV24RpcClient import org.bitcoins.rpc.client.v25.BitcoindV25RpcClient import org.bitcoins.rpc.config._ import org.bitcoins.rpc.util.{NodePair, RpcUtil} @@ -177,7 +176,7 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { version match { // default to newest version case Unknown => getBinary(BitcoindVersion.newest, binaryDirectory) - case known @ (V24 | V25) => + case known @ (V25) => val fileList = Files .list(binaryDirectory) .iterator() @@ -241,22 +240,6 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { BitcoindInstanceLocal.fromConfig(conf, binary) } - def v24Instance( - port: Int = RpcUtil.randomPort, - rpcPort: Int = RpcUtil.randomPort, - zmqConfig: ZmqConfig = RpcUtil.zmqConfig, - pruneMode: Boolean = false, - binaryDirectory: Path = BitcoindRpcTestClient.sbtBinaryDirectory - )(implicit system: ActorSystem): BitcoindInstanceLocal = - instance( - port = port, - rpcPort = rpcPort, - zmqConfig = zmqConfig, - pruneMode = pruneMode, - versionOpt = Some(BitcoindVersion.V24), - binaryDirectory = binaryDirectory - ) - def v25Instance( port: Int = RpcUtil.randomPort, rpcPort: Int = RpcUtil.randomPort, @@ -283,14 +266,6 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { binaryDirectory: Path = BitcoindRpcTestClient.sbtBinaryDirectory )(implicit system: ActorSystem): BitcoindInstanceLocal = { bitcoindVersion match { - case BitcoindVersion.V24 => - BitcoindRpcTestUtil.v24Instance( - port, - rpcPort, - zmqConfig, - pruneMode, - binaryDirectory = binaryDirectory - ) case BitcoindVersion.V25 => BitcoindRpcTestUtil.v25Instance( port, @@ -311,9 +286,8 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { )(implicit ec: ExecutionContext): Future[Unit] = { val startedServersF = Future.traverse(servers) { server => server.start().flatMap { res => + val descriptors = true val createWalletF = for { - version <- server.version - descriptors = true _ <- res.createWallet(BitcoindRpcClient.DEFAULT_WALLET_NAME, descriptors = descriptors) } yield res @@ -638,10 +612,6 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { val rpc = version match { case BitcoindVersion.Unknown => BitcoindRpcClient.withActorSystem(BitcoindRpcTestUtil.instance()) - case BitcoindVersion.V24 => - BitcoindV24RpcClient.withActorSystem( - BitcoindRpcTestUtil.v24Instance() - ) case BitcoindVersion.V25 => BitcoindV25RpcClient.withActorSystem( BitcoindRpcTestUtil.v25Instance()) diff --git a/testkit/src/main/scala/org/bitcoins/testkit/rpc/CachedBitcoind.scala b/testkit/src/main/scala/org/bitcoins/testkit/rpc/CachedBitcoind.scala index c024a6994f..e611bb388a 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/rpc/CachedBitcoind.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/rpc/CachedBitcoind.scala @@ -1,7 +1,6 @@ package org.bitcoins.testkit.rpc import org.bitcoins.rpc.client.common.{BitcoindRpcClient, BitcoindVersion} -import org.bitcoins.rpc.client.v24.BitcoindV24RpcClient import org.bitcoins.rpc.util.{NodePair, NodeTriple} import org.bitcoins.testkit.fixtures.BitcoinSFixture import org.bitcoins.testkit.util.BitcoinSPekkoAsyncTest @@ -80,6 +79,7 @@ trait CachedBitcoindFunded[T <: BitcoindRpcClient] extends CachedBitcoind[T] { if (isBitcoindUsed.get()) { // if it was used, shut down the cached bitcoind val stoppedF = for { + _ <- Future.unit cachedBitcoind <- cachedBitcoindWithFundsF _ <- BitcoindRpcTestUtil.stopServer(cachedBitcoind) } yield { @@ -128,18 +128,6 @@ trait CachedBitcoindBlockFilterRpcNewest } } -trait CachedBitcoindV24 extends CachedBitcoindFunded[BitcoindV24RpcClient] { - _: BitcoinSPekkoAsyncTest => - - override protected lazy val cachedBitcoindWithFundsF - : Future[BitcoindV24RpcClient] = { - val _ = isBitcoindUsed.set(true) - BitcoinSFixture - .createBitcoindWithFunds(Some(BitcoindVersion.V24)) - .map(_.asInstanceOf[BitcoindV24RpcClient]) - } -} - trait CachedBitcoindCollection[T <: BitcoindRpcClient] extends CachedBitcoind[T] { _: BitcoinSPekkoAsyncTest =>