From f75a52b5214bbe6967e2fb08479029c359fbb201 Mon Sep 17 00:00:00 2001 From: Chris Stewart Date: Mon, 28 Oct 2024 12:52:53 -0500 Subject: [PATCH] Refactor `TransactionProcessing.processTransaction()` to use `BlockHashWithConfs` (#5744) * Refactor TransactionProcessing.processTransaction() to use BlockHashWithConfs Create WalletUtil.getBlockHashWithConfs(), use it in various places through the codebase * Fix docs --- .../bitcoins/server/util/CallbackUtil.scala | 4 +- .../api/wallet/TransactionProcessingApi.scala | 9 +- .../dlc/wallet/DLCWalletCallbackTest.scala | 9 +- .../org/bitcoins/dlc/wallet/DLCWallet.scala | 3 +- .../internal/DLCTransactionProcessing.scala | 26 +-- docs/wallet/wallet.md | 7 +- .../testkit/chain/MockChainQueryApi.scala | 7 +- .../testkit/wallet/FundWalletUtil.scala | 6 +- .../wallet/ProcessTransactionTest.scala | 7 +- .../bitcoins/wallet/RescanHandlingTest.scala | 22 ++- .../bitcoins/wallet/UTXOLifeCycleTest.scala | 30 ++-- .../wallet/WalletIntegrationTest.scala | 35 +++- .../bitcoins/wallet/WalletSendingTest.scala | 11 +- .../org/bitcoins/wallet/WalletUnitTest.scala | 28 ++-- .../scala/org/bitcoins/wallet/Wallet.scala | 3 +- .../internal/SendFundsHandlingHandling.scala | 2 +- .../internal/TransactionProcessing.scala | 155 ++++++++---------- .../wallet/internal/UtxoHandling.scala | 6 +- .../org/bitcoins/wallet/util/WalletUtil.scala | 30 ++++ 19 files changed, 240 insertions(+), 160 deletions(-) create mode 100644 wallet/src/main/scala/org/bitcoins/wallet/util/WalletUtil.scala diff --git a/app/server/src/main/scala/org/bitcoins/server/util/CallbackUtil.scala b/app/server/src/main/scala/org/bitcoins/server/util/CallbackUtil.scala index 4a39ca0d57..c9c43ff05e 100644 --- a/app/server/src/main/scala/org/bitcoins/server/util/CallbackUtil.scala +++ b/app/server/src/main/scala/org/bitcoins/server/util/CallbackUtil.scala @@ -25,7 +25,7 @@ object CallbackUtil extends BitcoinSLogger { val txSink = Sink.foreachAsync[Transaction](1) { case tx: Transaction => logger.debug(s"Receiving transaction txid=${tx.txIdBE.hex} as a callback") wallet.transactionProcessing - .processTransaction(tx, blockHashOpt = None) + .processTransaction(tx, blockHashWithConfsOpt = None) .map(_ => ()) } @@ -109,7 +109,7 @@ object CallbackUtil extends BitcoinSLogger { val txSink = Sink.foreachAsync[Transaction](1) { case tx: Transaction => logger.debug(s"Receiving transaction txid=${tx.txIdBE.hex} as a callback") wallet.transactionProcessing - .processTransaction(tx, blockHashOpt = None) + .processTransaction(tx, blockHashWithConfsOpt = None) .map(_ => ()) } val onTx: OnTxReceived = { tx => diff --git a/core/src/main/scala/org/bitcoins/core/api/wallet/TransactionProcessingApi.scala b/core/src/main/scala/org/bitcoins/core/api/wallet/TransactionProcessingApi.scala index 1bccd0c3da..9cc79d7f89 100644 --- a/core/src/main/scala/org/bitcoins/core/api/wallet/TransactionProcessingApi.scala +++ b/core/src/main/scala/org/bitcoins/core/api/wallet/TransactionProcessingApi.scala @@ -4,6 +4,7 @@ import org.bitcoins.core.api.wallet.db.{SpendingInfoDb, TransactionDb} import org.bitcoins.core.currency.CurrencyUnit import org.bitcoins.core.protocol.blockchain.Block import org.bitcoins.core.protocol.transaction.{OutputWithIndex, Transaction} +import org.bitcoins.core.util.BlockHashWithConfs import org.bitcoins.core.wallet.fee.FeeUnit import org.bitcoins.core.wallet.utxo.AddressTag import org.bitcoins.crypto.{DoubleSha256Digest, DoubleSha256DigestBE} @@ -26,7 +27,7 @@ trait TransactionProcessingApi { def processTransaction( transaction: Transaction, - blockHashOpt: Option[DoubleSha256DigestBE] + blockHashWithConfsOpt: Option[BlockHashWithConfs] ): Future[Unit] /** Processes TXs originating from our wallet. This is called right after @@ -37,7 +38,7 @@ trait TransactionProcessingApi { feeRate: FeeUnit, inputAmount: CurrencyUnit, sentAmount: CurrencyUnit, - blockHashOpt: Option[DoubleSha256DigestBE], + blockHashWithConfsOpt: Option[BlockHashWithConfs], newTags: Vector[AddressTag] ): Future[ProcessTxResult] @@ -52,7 +53,7 @@ trait TransactionProcessingApi { def processReceivedUtxos( tx: Transaction, - blockHashOpt: Option[DoubleSha256DigestBE], + blockHashWithConfsOpt: Option[BlockHashWithConfs], spendingInfoDbs: Vector[SpendingInfoDb], newTags: Vector[AddressTag], relevantReceivedOutputs: Vector[OutputWithIndex] @@ -61,7 +62,7 @@ trait TransactionProcessingApi { def processSpentUtxos( transaction: Transaction, outputsBeingSpent: Vector[SpendingInfoDb], - blockHashOpt: Option[DoubleSha256DigestBE] + blockHashWithConfsOpt: Option[BlockHashWithConfs] ): Future[Vector[SpendingInfoDb]] def insertTransaction( diff --git a/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/DLCWalletCallbackTest.scala b/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/DLCWalletCallbackTest.scala index 680061b115..8903f0bffb 100644 --- a/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/DLCWalletCallbackTest.scala +++ b/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/DLCWalletCallbackTest.scala @@ -5,6 +5,7 @@ import org.bitcoins.core.protocol.dlc.models.{ DLCStatus, SingleContractInfo } +import org.bitcoins.core.util.BlockHashWithConfs import org.bitcoins.dlc.wallet.callback.{DLCWalletCallbacks, OnDLCStateChange} import org.bitcoins.testkit.wallet.FundWalletUtil.FundedDLCWallet import org.bitcoins.testkit.wallet.{BitcoinSDualWalletTest, DLCWalletUtil} @@ -96,9 +97,11 @@ class DLCWalletCallbackTest extends BitcoinSDualWalletTest { _ <- initF contractId <- DLCWalletUtil.getContractId(wallets._1.wallet) fundingTx <- walletA.getDLCFundingTx(contractId) + blockHash = CryptoGenerators.doubleSha256DigestBE.sample.get + blockHashWithConfs = BlockHashWithConfs(blockHash, Some(1)) _ <- walletA.transactionProcessing.processTransaction( transaction = fundingTx, - blockHashOpt = Some(CryptoGenerators.doubleSha256DigestBE.sample.get) + blockHashWithConfsOpt = Some(blockHashWithConfs) ) sigs = { DLCWalletUtil.sampleContractInfo match { @@ -207,9 +210,11 @@ class DLCWalletCallbackTest extends BitcoinSDualWalletTest { _ <- initF contractId <- DLCWalletUtil.getContractId(wallets._1.wallet) fundingTx <- walletA.getDLCFundingTx(contractId) + blockHash = CryptoGenerators.doubleSha256DigestBE.sample.get + blockHashWithConfs = BlockHashWithConfs(blockHash, Some(1)) _ <- walletA.transactionProcessing.processTransaction( transaction = fundingTx, - blockHashOpt = Some(CryptoGenerators.doubleSha256DigestBE.sample.get) + blockHashWithConfsOpt = Some(blockHashWithConfs) ) transaction <- walletA.executeDLCRefund(contractId) _ <- walletB.transactionProcessing.processTransaction(transaction, None) diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/DLCWallet.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/DLCWallet.scala index f29ccef6f2..6c0273531b 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/DLCWallet.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/DLCWallet.scala @@ -1935,7 +1935,8 @@ case class DLCWallet(override val walletApi: Wallet)(implicit _ <- updateClosingTxId(contractId, refundTx.txIdBE) _ <- transactionProcessing.processTransaction(refundTx, - blockHashOpt = None) + blockHashWithConfsOpt = + None) status <- findDLC(dlcDb.dlcId) _ <- dlcConfig.walletCallbacks.executeOnDLCStateChange(status.get) } yield refundTx diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/internal/DLCTransactionProcessing.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/internal/DLCTransactionProcessing.scala index 33b49a0586..da09aa6e52 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/internal/DLCTransactionProcessing.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/internal/DLCTransactionProcessing.scala @@ -22,7 +22,7 @@ import org.bitcoins.core.protocol.transaction.{ WitnessTransaction } import org.bitcoins.core.psbt.InputPSBTRecord.PartialSignature -import org.bitcoins.core.util.FutureUtil +import org.bitcoins.core.util.{BlockHashWithConfs, FutureUtil} import org.bitcoins.core.wallet.fee.FeeUnit import org.bitcoins.core.wallet.utxo.{ AddressTag, @@ -519,23 +519,25 @@ case class DLCTransactionProcessing( override def processTransaction( transaction: Transaction, - blockHashOpt: Option[DoubleSha256DigestBE]): Future[Unit] = { + blockHashWithConfsOpt: Option[BlockHashWithConfs]): Future[Unit] = { txProcessing - .processTransaction(transaction, blockHashOpt) - .flatMap(_ => processFundingTx(transaction, blockHashOpt)) - .flatMap(_ => processSettledDLCs(transaction, blockHashOpt)) + .processTransaction(transaction, blockHashWithConfsOpt) + .flatMap(_ => + processFundingTx(transaction, blockHashWithConfsOpt.map(_.blockHash))) + .flatMap(_ => + processSettledDLCs(transaction, blockHashWithConfsOpt.map(_.blockHash))) .map(_ => ()) } override def processReceivedUtxos( tx: Transaction, - blockHashOpt: Option[DoubleSha256DigestBE], + blockHashWithConfsOpt: Option[BlockHashWithConfs], spendingInfoDbs: Vector[SpendingInfoDb], newTags: Vector[AddressTag], relevantReceivedOutputs: Vector[OutputWithIndex]) : Future[Vector[SpendingInfoDb]] = { txProcessing.processReceivedUtxos(tx, - blockHashOpt, + blockHashWithConfsOpt, spendingInfoDbs, newTags, relevantReceivedOutputs) @@ -544,9 +546,11 @@ case class DLCTransactionProcessing( override def processSpentUtxos( transaction: Transaction, outputsBeingSpent: Vector[SpendingInfoDb], - blockHashOpt: Option[DoubleSha256DigestBE]) + blockHashWithConfsOpt: Option[BlockHashWithConfs]) : Future[Vector[SpendingInfoDb]] = { - txProcessing.processSpentUtxos(transaction, outputsBeingSpent, blockHashOpt) + txProcessing.processSpentUtxos(transaction, + outputsBeingSpent, + blockHashWithConfsOpt) } /** Processes TXs originating from our wallet. This is called right after @@ -557,13 +561,13 @@ case class DLCTransactionProcessing( feeRate: FeeUnit, inputAmount: CurrencyUnit, sentAmount: CurrencyUnit, - blockHashOpt: Option[DoubleSha256DigestBE], + blockHashWithConfsOpt: Option[BlockHashWithConfs], newTags: Vector[AddressTag]): Future[ProcessTxResult] = { txProcessing.processOurTransaction(transaction, feeRate, inputAmount, sentAmount, - blockHashOpt, + blockHashWithConfsOpt, newTags) } diff --git a/docs/wallet/wallet.md b/docs/wallet/wallet.md index 367e3fe2f9..70bdbd7835 100644 --- a/docs/wallet/wallet.md +++ b/docs/wallet/wallet.md @@ -64,7 +64,9 @@ import org.bitcoins.rpc.client.common.BitcoindRpcClient import org.bitcoins.rpc.config._ import org.bitcoins.wallet.config.WalletAppConfig import org.bitcoins.core.api.wallet.WalletApi +import org.bitcoins.core.util.BlockHashWithConfs import org.bitcoins.wallet.Wallet +import org.bitcoins.wallet.util.WalletUtil import com.typesafe.config.ConfigFactory import java.nio.file.Files @@ -157,12 +159,13 @@ val walletF: Future[WalletApi] = configF.flatMap { _ => // when this future completes, ww have sent a transaction // from bitcoind to the Bitcoin-S wallet -val transactionF: Future[(Transaction, Option[DoubleSha256DigestBE])] = for { +val transactionF: Future[(Transaction, Option[BlockHashWithConfs])] = for { wallet <- walletF address <- wallet.getNewAddress() txid <- bitcoind.sendToAddress(address, 3.bitcoin) transaction <- bitcoind.getRawTransaction(txid) -} yield (transaction.hex, transaction.blockhash) + blockHashWithConfs <- WalletUtil.getBlockHashWithConfs(bitcoind,transaction.blockhash) +} yield (transaction.hex, blockHashWithConfs) // when this future completes, we have processed // the transaction from bitcoind, and we have diff --git a/testkit/src/main/scala/org/bitcoins/testkit/chain/MockChainQueryApi.scala b/testkit/src/main/scala/org/bitcoins/testkit/chain/MockChainQueryApi.scala index 7a86587466..40af8d2794 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/chain/MockChainQueryApi.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/chain/MockChainQueryApi.scala @@ -5,7 +5,7 @@ import org.bitcoins.core.api.chain.ChainQueryApi.FilterResponse import org.bitcoins.core.gcs.BlockFilter import org.bitcoins.core.protocol.BlockStamp import org.bitcoins.core.protocol.blockchain.RegTestNetChainParams -import org.bitcoins.core.util.FutureUtil +import org.bitcoins.core.util.{BlockHashWithConfs, FutureUtil} import org.bitcoins.crypto.DoubleSha256DigestBE import scala.concurrent.Future @@ -19,6 +19,9 @@ object MockChainQueryApi extends ChainQueryApi { "00000000496dcc754fabd97f3e2df0a7337eab417d75537fecf97a7ebb0e7c75" ) + val blockHashWithConfs: BlockHashWithConfs = + BlockHashWithConfs(testBlockHash, Some(6)) + /** Gets the height of the given block */ override def getBlockHeight( blockHash: DoubleSha256DigestBE @@ -41,7 +44,7 @@ object MockChainQueryApi extends ChainQueryApi { blockHash: DoubleSha256DigestBE ): Future[Option[Int]] = { if (blockHash == testBlockHash) { - Future.successful(Some(6)) + Future.successful(blockHashWithConfs.confirmationsOpt) } else FutureUtil.none } diff --git a/testkit/src/main/scala/org/bitcoins/testkit/wallet/FundWalletUtil.scala b/testkit/src/main/scala/org/bitcoins/testkit/wallet/FundWalletUtil.scala index 66541ed585..bed602fb11 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/wallet/FundWalletUtil.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/wallet/FundWalletUtil.scala @@ -25,6 +25,7 @@ import org.bitcoins.testkit.wallet.FundWalletUtil.{ import org.bitcoins.testkitcore.gen.TransactionGenerators import org.bitcoins.testkitcore.util.TransactionTestUtil import org.bitcoins.wallet.config.WalletAppConfig +import org.bitcoins.wallet.util.WalletUtil import scala.concurrent.{ExecutionContext, Future} @@ -107,7 +108,10 @@ trait FundWalletUtil extends BitcoinSLogger { addresses <- addressesF addressAmountMap = addresses.zip(amts).toMap (tx, blockHash) <- fundAddressesWithBitcoind(addressAmountMap, bitcoind) - _ <- wallet.transactionProcessing.processTransaction(tx, Some(blockHash)) + blockHashWithConfs <- WalletUtil.getBlockHashWithConfs(bitcoind, + blockHash) + _ <- wallet.transactionProcessing.processTransaction(tx, + blockHashWithConfs) } yield (tx, blockHash) txAndHashF.map(_ => wallet) diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/ProcessTransactionTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/ProcessTransactionTest.scala index 8a0948d1ea..3258063997 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/ProcessTransactionTest.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/ProcessTransactionTest.scala @@ -75,17 +75,18 @@ class ProcessTransactionTest extends BitcoinSWalletTest { _ <- wallet.transactionProcessing.processTransaction( tx, - Some(MockChainQueryApi.testBlockHash) + Some(MockChainQueryApi.blockHashWithConfs) ) newConfirmed <- wallet.getConfirmedBalance() newUnconfirmed <- wallet.getUnconfirmedBalance() utxosPostAdd <- wallet.utxoHandling.listUtxos() // repeating the action should not make a difference + _ <- checkUtxosAndBalance(wallet) { wallet.transactionProcessing.processTransaction( tx, - Some(MockChainQueryApi.testBlockHash)) + Some(MockChainQueryApi.blockHashWithConfs)) } } yield { val ourOutputs = @@ -196,7 +197,7 @@ class ProcessTransactionTest extends BitcoinSWalletTest { ) _ <- wallet.transactionProcessing.processTransaction( transaction = rawTxHelper.signedTx, - blockHashOpt = None + blockHashWithConfsOpt = None ) balance <- wallet.getBalance() } yield assert(balance == amount) diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/RescanHandlingTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/RescanHandlingTest.scala index ac41480df1..87e3bbe615 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/RescanHandlingTest.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/RescanHandlingTest.scala @@ -11,6 +11,8 @@ import org.bitcoins.testkit.wallet.{ BitcoinSWalletTestCachedBitcoindNewest, WalletWithBitcoindRpc } +import org.bitcoins.wallet.util.WalletUtil + import scala.concurrent.duration.DurationInt class RescanHandlingTest extends BitcoinSWalletTestCachedBitcoindNewest { @@ -110,9 +112,12 @@ class RescanHandlingTest extends BitcoinSWalletTestCachedBitcoindNewest { bitcoindAddr <- bitcoindAddrF blockHashes <- bitcoind.generateToAddress(blocks = numBlocks, address = bitcoindAddr) + blockHashWithConfs <- WalletUtil.getBlockHashWithConfs( + bitcoind, + blockHashes.headOption) _ <- wallet.transactionProcessing.processTransaction( transaction = tx, - blockHashOpt = blockHashes.headOption + blockHashWithConfsOpt = blockHashWithConfs ) balance <- wallet.getBalance() unconfirmedBalance <- wallet.getUnconfirmedBalance() @@ -171,9 +176,12 @@ class RescanHandlingTest extends BitcoinSWalletTestCachedBitcoindNewest { bitcoindAddr <- bitcoindAddrF blockHashes <- bitcoind.generateToAddress(blocks = numBlocks, address = bitcoindAddr) + blockHashWithConfs <- WalletUtil.getBlockHashWithConfs( + bitcoind, + blockHashes.headOption) _ <- wallet.transactionProcessing.processTransaction( transaction = tx, - blockHashOpt = blockHashes.headOption + blockHashWithConfsOpt = blockHashWithConfs ) balance <- wallet.getBalance() unconfirmedBalance <- wallet.getUnconfirmedBalance() @@ -235,9 +243,12 @@ class RescanHandlingTest extends BitcoinSWalletTestCachedBitcoindNewest { bitcoindAddr <- bitcoindAddrF blockHashes <- bitcoind.generateToAddress(blocks = numBlocks, address = bitcoindAddr) + blockHashWithConfs <- WalletUtil.getBlockHashWithConfs( + bitcoind, + blockHashes.headOption) _ <- wallet.transactionProcessing.processTransaction( transaction = tx, - blockHashOpt = blockHashes.headOption + blockHashWithConfsOpt = blockHashWithConfs ) balance <- wallet.getBalance() unconfirmedBalance <- wallet.getUnconfirmedBalance() @@ -523,9 +534,12 @@ class RescanHandlingTest extends BitcoinSWalletTestCachedBitcoindNewest { bitcoindAddr <- bitcoindAddrF blockHashes <- bitcoind.generateToAddress(blocks = numBlocks, address = bitcoindAddr) + blockHashWithConfs <- WalletUtil.getBlockHashWithConfs( + bitcoind, + blockHashes.headOption) _ <- wallet.transactionProcessing.processTransaction( transaction = tx, - blockHashOpt = blockHashes.headOption + blockHashWithConfsOpt = blockHashWithConfs ) balance <- wallet.getBalance() unconfirmedBalance <- wallet.getUnconfirmedBalance() diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/UTXOLifeCycleTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/UTXOLifeCycleTest.scala index a7085357c2..f847d60b67 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/UTXOLifeCycleTest.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/UTXOLifeCycleTest.scala @@ -4,21 +4,22 @@ import org.bitcoins.commons.util.BitcoinSLogger import org.bitcoins.core.api.wallet.CoinSelectionAlgo import org.bitcoins.core.api.wallet.db.SpendingInfoDb import org.bitcoins.core.currency.{Bitcoins, Satoshis} -import org.bitcoins.core.number._ +import org.bitcoins.core.number.* import org.bitcoins.core.protocol.BitcoinAddress -import org.bitcoins.core.protocol.script._ -import org.bitcoins.core.protocol.transaction._ +import org.bitcoins.core.protocol.script.* +import org.bitcoins.core.protocol.transaction.* import org.bitcoins.core.psbt.PSBT import org.bitcoins.core.wallet.builder.RawTxSigner import org.bitcoins.core.wallet.fee.{SatoshisPerByte, SatoshisPerVirtualByte} import org.bitcoins.core.wallet.utxo.TxoState -import org.bitcoins.core.wallet.utxo.TxoState._ +import org.bitcoins.core.wallet.utxo.TxoState.* import org.bitcoins.crypto.{DoubleSha256DigestBE, ECPublicKey} import org.bitcoins.testkit.wallet.{ BitcoinSWalletTestCachedBitcoindNewest, WalletWithBitcoindRpc } import org.bitcoins.wallet.models.SpendingInfoDAO +import org.bitcoins.wallet.util.WalletUtil import org.scalatest.{Assertion, FutureOutcome, Outcome} import scala.concurrent.Future @@ -83,7 +84,9 @@ class UTXOLifeCycleTest // Give tx a fake hash so it can appear as it's in a block hash <- bitcoind.getBestBlockHash() - _ <- wallet.transactionProcessing.processTransaction(tx, Some(hash)) + blockHashWithConfs <- WalletUtil.getBlockHashWithConfs(bitcoind, hash) + _ <- wallet.transactionProcessing.processTransaction(tx, + blockHashWithConfs) _ <- wallet.utxoHandling.updateUtxoPendingStates() pendingCoins <- wallet.utxoHandling.findOutputsBeingSpent(tx) @@ -345,7 +348,9 @@ class UTXOLifeCycleTest // Give tx a fake hash so it can appear as it's in a block hash <- bitcoind.getBestBlockHash() - _ <- wallet.transactionProcessing.processTransaction(tx, Some(hash)) + blockHashWithConfs <- WalletUtil.getBlockHashWithConfs(bitcoind, hash) + _ <- wallet.transactionProcessing.processTransaction(tx, + blockHashWithConfs) _ <- wallet.utxoHandling.updateUtxoPendingStates() pendingCoins <- wallet.utxoHandling.findOutputsBeingSpent(tx) @@ -390,7 +395,7 @@ class UTXOLifeCycleTest feeRate = SatoshisPerByte(Satoshis(3)), inputAmount = Satoshis(4000), sentAmount = Satoshis(3000), - blockHashOpt = None, + blockHashWithConfsOpt = None, newTags = Vector.empty ) @@ -419,7 +424,7 @@ class UTXOLifeCycleTest feeRate = SatoshisPerByte(Satoshis(3)), inputAmount = Satoshis(4000), sentAmount = Satoshis(3000), - blockHashOpt = None, + blockHashWithConfsOpt = None, newTags = Vector.empty ) @@ -431,7 +436,10 @@ class UTXOLifeCycleTest hash <- bitcoind.getNewAddress .flatMap(bitcoind.generateToAddress(1, _)) .map(_.head) - _ <- wallet.transactionProcessing.processTransaction(tx, Some(hash)) + blockHashWithConfsOpt <- WalletUtil.getBlockHashWithConfs(bitcoind, hash) + _ <- wallet.transactionProcessing.processTransaction( + tx, + blockHashWithConfsOpt) pendingCoins <- wallet.utxoHandling.findByScriptPubKey(addr.scriptPubKey) @@ -456,12 +464,14 @@ class UTXOLifeCycleTest txId <- bitcoind.sendToAddress(addr, Satoshis(3000)) tx <- bitcoind.getRawTransactionRaw(txId) + blockHashWithConfsOpt <- WalletUtil.getBlockHashWithConfs(bitcoind, + Some(blockHash)) _ <- wallet.transactionProcessing.processOurTransaction( transaction = tx, feeRate = SatoshisPerByte(Satoshis(3)), inputAmount = Satoshis(4000), sentAmount = Satoshis(3000), - blockHashOpt = Some(blockHash), // give fake hash + blockHashWithConfsOpt = blockHashWithConfsOpt, // give fake hash newTags = Vector.empty ) diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/WalletIntegrationTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/WalletIntegrationTest.scala index 9a913732e2..484f1d7b64 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/WalletIntegrationTest.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/WalletIntegrationTest.scala @@ -19,6 +19,7 @@ import org.bitcoins.wallet.models.{ IncomingTransactionDAO, OutgoingTransactionDAO } +import org.bitcoins.wallet.util.WalletUtil import org.scalatest.{FutureOutcome, Outcome} import scala.concurrent.Future @@ -92,7 +93,11 @@ class WalletIntegrationTest extends BitcoinSWalletTestCachedBitcoindNewest { rawTx <- bitcoind.getRawTransaction(txId) // after this, tx should be confirmed - _ <- wallet.transactionProcessing.processTransaction(tx, rawTx.blockhash) + blockHashWithConfsOpt <- WalletUtil.getBlockHashWithConfs(bitcoind, + rawTx.blockhash) + _ <- wallet.transactionProcessing.processTransaction( + tx, + blockHashWithConfsOpt) _ <- wallet.utxoHandling .listUtxos() @@ -176,8 +181,11 @@ class WalletIntegrationTest extends BitcoinSWalletTestCachedBitcoindNewest { txId <- bitcoind.sendToAddress(addr, valueFromBitcoind) rawTx <- bitcoind.getRawTransaction(txId) _ <- bitcoind.generate(6) - _ <- wallet.transactionProcessing.processTransaction(rawTx.hex, - rawTx.blockhash) + blockHashWithConfsOpt <- WalletUtil.getBlockHashWithConfs(bitcoind, + rawTx.blockhash) + _ <- wallet.transactionProcessing.processTransaction( + rawTx.hex, + blockHashWithConfsOpt) // Verify we funded the wallet balance <- wallet.getBalance() @@ -243,8 +251,11 @@ class WalletIntegrationTest extends BitcoinSWalletTestCachedBitcoindNewest { txId <- bitcoind.sendToAddress(addr, valueFromBitcoind) _ <- bitcoind.generate(6) rawTx <- bitcoind.getRawTransaction(txId) - _ <- wallet.transactionProcessing.processTransaction(rawTx.hex, - rawTx.blockhash) + blockHashWithConfsOpt <- WalletUtil.getBlockHashWithConfs(bitcoind, + rawTx.blockhash) + _ <- wallet.transactionProcessing.processTransaction( + rawTx.hex, + blockHashWithConfsOpt) // Verify we funded the wallet balance <- wallet.getBalance() @@ -262,8 +273,11 @@ class WalletIntegrationTest extends BitcoinSWalletTestCachedBitcoindNewest { _ <- bitcoind.generate(1) rawTx1 <- bitcoind.getRawTransaction(rbf.txIdBE) _ = require(rawTx1.blockhash.isDefined) - _ <- wallet.transactionProcessing.processTransaction(rbf, - rawTx1.blockhash) + blockHashWithConfsOpt <- WalletUtil.getBlockHashWithConfs(bitcoind, + rawTx.blockhash) + _ <- wallet.transactionProcessing.processTransaction( + rbf, + blockHashWithConfsOpt) // fail to RBF confirmed tx res <- recoverToSucceededIf[IllegalArgumentException] { @@ -283,8 +297,11 @@ class WalletIntegrationTest extends BitcoinSWalletTestCachedBitcoindNewest { txId <- bitcoind.sendToAddress(addr, valueFromBitcoind) rawTx <- bitcoind.getRawTransaction(txId) _ <- bitcoind.generate(6) - _ <- wallet.transactionProcessing.processTransaction(rawTx.hex, - rawTx.blockhash) + blockHashWithConfsOpt <- WalletUtil.getBlockHashWithConfs(bitcoind, + rawTx.blockhash) + _ <- wallet.transactionProcessing.processTransaction( + rawTx.hex, + blockHashWithConfsOpt) // Verify we funded the wallet balance <- wallet.getBalance() diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/WalletSendingTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/WalletSendingTest.scala index 382c50f5b1..1453c61456 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/WalletSendingTest.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/WalletSendingTest.scala @@ -19,6 +19,7 @@ import org.bitcoins.testkitcore.Implicits.GeneratorOps import org.bitcoins.testkitcore.gen.FeeUnitGen import org.bitcoins.wallet.config.WalletAppConfig import org.bitcoins.wallet.models.{OutgoingTransactionDAO, SpendingInfoDAO} +import org.bitcoins.wallet.util.WalletUtil import org.scalatest.{Assertion, FutureOutcome} import scodec.bits.ByteVector @@ -379,9 +380,12 @@ class WalletSendingTest extends BitcoinSWalletTest { tx <- wallet.sendFundsHandling.sendToAddress(testAddress, amountToSend, feeRate) + blockHashWithConfsOpt <- WalletUtil.getBlockHashWithConfs( + chainQueryApi, + Some(DoubleSha256DigestBE.empty)) _ <- wallet.transactionProcessing.processTransaction( tx, - Some(DoubleSha256DigestBE.empty)) + blockHashWithConfsOpt) res <- recoverToSucceededIf[IllegalArgumentException] { wallet.sendFundsHandling.bumpFeeRBF(tx.txIdBE, newFeeRate) @@ -470,9 +474,12 @@ class WalletSendingTest extends BitcoinSWalletTest { tx <- wallet.sendFundsHandling.sendToAddress(testAddress, amountToSend, feeRate) + blockHashWithConfsOpt <- WalletUtil.getBlockHashWithConfs( + chainQueryApi, + Some(DoubleSha256DigestBE.empty)) _ <- wallet.transactionProcessing.processTransaction( tx, - Some(DoubleSha256DigestBE.empty)) + blockHashWithConfsOpt) res <- recoverToSucceededIf[IllegalArgumentException] { wallet.sendFundsHandling.bumpFeeCPFP(tx.txIdBE, feeRate) diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/WalletUnitTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/WalletUnitTest.scala index dd80e01727..23767fa594 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/WalletUnitTest.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/WalletUnitTest.scala @@ -254,9 +254,9 @@ class WalletUnitTest extends BitcoinSWalletTest { spk = addr.scriptPubKey _ = assert(spk == P2PKHScriptPubKey(walletKey)) dummyPrevTx = dummyTx(spk = spk) - _ <- wallet.transactionProcessing.processTransaction(dummyPrevTx, - blockHashOpt = - None) + _ <- wallet.transactionProcessing.processTransaction( + dummyPrevTx, + blockHashWithConfsOpt = None) psbt = dummyPSBT(prevTxId = dummyPrevTx.txId) @@ -280,9 +280,9 @@ class WalletUnitTest extends BitcoinSWalletTest { spk = addr.scriptPubKey _ = assert(spk == P2SHScriptPubKey(P2WPKHWitnessSPKV0(walletKey))) dummyPrevTx = dummyTx(spk = spk) - _ <- wallet.transactionProcessing.processTransaction(dummyPrevTx, - blockHashOpt = - None) + _ <- wallet.transactionProcessing.processTransaction( + dummyPrevTx, + blockHashWithConfsOpt = None) psbt = dummyPSBT(prevTxId = dummyPrevTx.txId) @@ -306,9 +306,9 @@ class WalletUnitTest extends BitcoinSWalletTest { spk = addr.scriptPubKey _ = assert(spk == P2WPKHWitnessSPKV0(walletKey)) dummyPrevTx = dummyTx(spk = spk) - _ <- wallet.transactionProcessing.processTransaction(dummyPrevTx, - blockHashOpt = - None) + _ <- wallet.transactionProcessing.processTransaction( + dummyPrevTx, + blockHashWithConfsOpt = None) psbt = dummyPSBT(prevTxId = dummyPrevTx.txId) .addUTXOToInput(dummyPrevTx, 0) @@ -339,12 +339,14 @@ class WalletUnitTest extends BitcoinSWalletTest { spk = addr.scriptPubKey _ = assert(spk == P2WPKHWitnessSPKV0(walletKey)) dummyPrevTx = dummyTx(spk = spk) - _ <- wallet.transactionProcessing.processTransaction(dummyPrevTx, - blockHashOpt = None) + _ <- wallet.transactionProcessing.processTransaction( + dummyPrevTx, + blockHashWithConfsOpt = None) dummyPrevTx1 = dummyTx(prevTxId = dummyPrevTx.txId, spk = spk) - _ <- wallet.transactionProcessing.processTransaction(dummyPrevTx1, - blockHashOpt = None) + _ <- wallet.transactionProcessing.processTransaction( + dummyPrevTx1, + blockHashWithConfsOpt = None) toBroadcast <- wallet.sendFundsHandling.getTransactionsToBroadcast } yield assert(toBroadcast.map(_.txIdBE) == Vector(dummyPrevTx1.txIdBE)) diff --git a/wallet/src/main/scala/org/bitcoins/wallet/Wallet.scala b/wallet/src/main/scala/org/bitcoins/wallet/Wallet.scala index b6f669bb8e..24527e362a 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/Wallet.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/Wallet.scala @@ -232,7 +232,8 @@ case class Wallet( for { _ <- nodeApi.broadcastTransaction(transaction) _ <- transactionProcessing.processTransaction(transaction, - blockHashOpt = None) + blockHashWithConfsOpt = + None) _ <- walletCallbacks.executeOnTransactionBroadcast(transaction) } yield () diff --git a/wallet/src/main/scala/org/bitcoins/wallet/internal/SendFundsHandlingHandling.scala b/wallet/src/main/scala/org/bitcoins/wallet/internal/SendFundsHandlingHandling.scala index ac973bbe47..7a173ef5f2 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/internal/SendFundsHandlingHandling.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/internal/SendFundsHandlingHandling.scala @@ -604,7 +604,7 @@ case class SendFundsHandlingHandling( feeRate = feeRate, inputAmount = creditingAmount, sentAmount = sentAmount, - blockHashOpt = None, + blockHashWithConfsOpt = None, newTags = newTags ) } yield { diff --git a/wallet/src/main/scala/org/bitcoins/wallet/internal/TransactionProcessing.scala b/wallet/src/main/scala/org/bitcoins/wallet/internal/TransactionProcessing.scala index 9e08082b8b..aa62ec9433 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/internal/TransactionProcessing.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/internal/TransactionProcessing.scala @@ -38,6 +38,7 @@ import org.bitcoins.wallet.models.{ WalletDAOs, WalletStateDescriptorDAO } +import org.bitcoins.wallet.util.WalletUtil import slick.dbio.{DBIOAction, Effect, NoStream} import scala.collection.mutable @@ -82,13 +83,13 @@ case class TransactionProcessing( /** @inheritdoc */ override def processTransaction( transaction: Transaction, - blockHashOpt: Option[DoubleSha256DigestBE] + blockHashWithConfsOpt: Option[BlockHashWithConfs] ): Future[Unit] = { for { relevantReceivedOutputs <- getRelevantOutputs(transaction) - action <- processTransactionImpl( + action = processTransactionImpl( transaction = transaction, - blockHashOpt = blockHashOpt, + blockHashWithConfsOpt = blockHashWithConfsOpt, newTags = Vector.empty, receivedSpendingInfoDbsOpt = None, spentSpendingInfoDbsOpt = None, @@ -187,7 +188,9 @@ case class TransactionProcessing( val spentSpendingInfoDbsF = spendingInfoDAO.findOutputsBeingSpent(block.transactions.toVector) - val blockHashOpt = Some(block.blockHeader.hash.flip) + val blockHash = block.blockHeader.hashBE + val blockHashWithConfsOptF: Future[Option[BlockHashWithConfs]] = + WalletUtil.getBlockHashWithConfs(chainQueryApi, blockHash) // fetch all outputs we may have received in this block in advance // as an optimization @@ -201,6 +204,7 @@ case class TransactionProcessing( spentSpendingInfoDbs <- spentSpendingInfoDbsF relevantReceivedOutputsForBlock <- relevantReceivedOutputsForBlockF + blockHashWithConfsOpt <- blockHashWithConfsOptF } yield { // we need to keep a cache of spentSpendingInfoDb // for the case where we receive & then spend that @@ -215,10 +219,10 @@ case class TransactionProcessing( _ <- walletF relevantReceivedOutputsForTx = relevantReceivedOutputsForBlock .getOrElse(transaction.txIdBE, Vector.empty) - action <- + action = processTransactionImpl( transaction = transaction, - blockHashOpt = blockHashOpt, + blockHashWithConfsOpt = blockHashWithConfsOpt, newTags = Vector.empty, receivedSpendingInfoDbsOpt = receivedSpendingInfoDbsOpt, spentSpendingInfoDbsOpt = cachedSpentOpt, @@ -314,12 +318,12 @@ case class TransactionProcessing( feeRate: FeeUnit, inputAmount: CurrencyUnit, sentAmount: CurrencyUnit, - blockHashOpt: Option[DoubleSha256DigestBE], + blockHashWithConfsOpt: Option[BlockHashWithConfs], newTags: Vector[AddressTag] ): Future[ProcessTxResult] = { logger.info( - s"Processing TX from our wallet, transaction=${transaction.txIdBE.hex} with blockHash=${blockHashOpt - .map(_.hex)}" + s"Processing TX from our wallet, transaction=${transaction.txIdBE.hex} with blockHash=${blockHashWithConfsOpt + .map(_.blockHash.hex)}" ) val relevantOutputsF = getRelevantOutputs(transaction) for { @@ -329,12 +333,12 @@ case class TransactionProcessing( feeRate, inputAmount, sentAmount, - blockHashOpt + blockHashWithConfsOpt.map(_.blockHash) ) relevantOutputs <- relevantOutputsF - action <- processTransactionImpl( + action = processTransactionImpl( transaction = txDb.transaction, - blockHashOpt = blockHashOpt, + blockHashWithConfsOpt = blockHashWithConfsOpt, newTags = newTags, receivedSpendingInfoDbsOpt = None, spentSpendingInfoDbsOpt = None, @@ -444,48 +448,30 @@ case class TransactionProcessing( */ override def processReceivedUtxos( transaction: Transaction, - blockHashOpt: Option[DoubleSha256DigestBE], + blockHashWithConfsOpt: Option[BlockHashWithConfs], spendingInfoDbs: Vector[SpendingInfoDb], newTags: Vector[AddressTag], relevantReceivedOutputs: Vector[OutputWithIndex] ): Future[Vector[SpendingInfoDb]] = { - val confsOptF: Future[Option[BlockHashWithConfs]] = blockHashOpt match { - case Some(blockHash) => - chainQueryApi - .getNumberOfConfirmations(blockHash) - .map(confsOpt => Some(BlockHashWithConfs(blockHash, confsOpt))) - case None => Future.successful(None) - } - val actionF = confsOptF.map { confsOpt => - processReceivedUtxosAction(transaction, - confsOpt, - spendingInfoDbs, - newTags, - relevantReceivedOutputs) - } - actionF.flatMap(a => safeDatabase.run(a)) + val action = processReceivedUtxosAction(transaction, + blockHashWithConfsOpt, + spendingInfoDbs, + newTags, + relevantReceivedOutputs) + safeDatabase.run(action) } override def processSpentUtxos( transaction: Transaction, outputsBeingSpent: Vector[SpendingInfoDb], - blockHashOpt: Option[DoubleSha256DigestBE] + blockHashWithConfsOpt: Option[BlockHashWithConfs] ): Future[Vector[SpendingInfoDb]] = { - val blockHashWithConfsF: Future[Option[BlockHashWithConfs]] = - blockHashOpt match { - case Some(blockHash) => - chainQueryApi - .getNumberOfConfirmations(blockHash) - .map(BlockHashWithConfs(blockHash, _)) - .map(Some.apply) - case None => Future.successful(None) - } - val actionF = blockHashWithConfsF.map { confsOpt => - processSpentUtxosAction(transaction, outputsBeingSpent, confsOpt) - } + val action = processSpentUtxosAction(transaction, + outputsBeingSpent, + blockHashWithConfsOpt) - actionF.flatMap(safeDatabase.run) + safeDatabase.run(action) } /** Searches for outputs on the given transaction that are being spent from @@ -521,17 +507,16 @@ case class TransactionProcessing( */ private[internal] def processTransactionImpl( transaction: Transaction, - blockHashOpt: Option[DoubleSha256DigestBE], + blockHashWithConfsOpt: Option[BlockHashWithConfs], newTags: Vector[AddressTag], receivedSpendingInfoDbsOpt: Option[Vector[SpendingInfoDb]], spentSpendingInfoDbsOpt: Option[Vector[SpendingInfoDb]], relevantReceivedOutputs: Vector[OutputWithIndex] - ): Future[ - DBIOAction[ProcessTxResult, NoStream, Effect.Read & Effect.Write]] = { + ): DBIOAction[ProcessTxResult, NoStream, Effect.Read & Effect.Write] = { logger.debug( - s"Processing transaction=${transaction.txIdBE.hex} with blockHash=${blockHashOpt - .map(_.hex)}" + s"Processing transaction=${transaction.txIdBE.hex} with blockHash=${blockHashWithConfsOpt + .map(_.blockHash.hex)}" ) val receivedSpendingInfoDbsA : DBIOAction[Vector[SpendingInfoDb], NoStream, Effect.Read] = { @@ -561,51 +546,43 @@ case class TransactionProcessing( spendingInfoDAO.findOutputsBeingSpentAction(Vector(transaction)) } } - val confsOptF: Future[Option[BlockHashWithConfs]] = blockHashOpt match { - case Some(blockHash) => - chainQueryApi - .getNumberOfConfirmations(blockHash) - .map(confsOpt => Some(BlockHashWithConfs(blockHash, confsOpt))) - case None => Future.successful(None) - } - val actionF: Future[ - DBIOAction[ProcessTxResult, NoStream, Effect.Write & Effect.Read]] = - confsOptF.map { confsOpt => - for { - receivedSpendingInfoDbs <- receivedSpendingInfoDbsA - receivedStart = TimeUtil.currentEpochMs - incoming <- processReceivedUtxosAction( - transaction = transaction, - blockHashWithConfsOpt = confsOpt, - spendingInfoDbs = receivedSpendingInfoDbs, - newTags = newTags, - relevantReceivedOutputs = relevantReceivedOutputs + val action + : DBIOAction[ProcessTxResult, NoStream, Effect.Write & Effect.Read] = + for { + receivedSpendingInfoDbs <- receivedSpendingInfoDbsA + receivedStart = TimeUtil.currentEpochMs + incoming <- processReceivedUtxosAction( + transaction = transaction, + blockHashWithConfsOpt = blockHashWithConfsOpt, + spendingInfoDbs = receivedSpendingInfoDbs, + newTags = newTags, + relevantReceivedOutputs = relevantReceivedOutputs + ) + _ = if (incoming.nonEmpty) { + logger.info( + s"Finished processing ${incoming.length} received outputs, balance=${incoming + .map(_.output.value) + .sum} it took=${TimeUtil.currentEpochMs - receivedStart}ms" ) - _ = if (incoming.nonEmpty) { - logger.info( - s"Finished processing ${incoming.length} received outputs, balance=${incoming - .map(_.output.value) - .sum} it took=${TimeUtil.currentEpochMs - receivedStart}ms" - ) - } - - spentSpendingInfoDbs <- spentSpendingInfoDbsF - spentStart = TimeUtil.currentEpochMs - outgoing <- processSpentUtxosAction( - transaction = transaction, - outputsBeingSpent = spentSpendingInfoDbs, - blockHashWithConfs = confsOpt - ) - _ = if (outgoing.nonEmpty) { - logger.info( - s"Finished processing ${outgoing.length} spent outputs, it took=${TimeUtil.currentEpochMs - spentStart}ms" - ) - } - } yield { - ProcessTxResult(incoming, outgoing) } + + spentSpendingInfoDbs <- spentSpendingInfoDbsF + spentStart = TimeUtil.currentEpochMs + outgoing <- processSpentUtxosAction( + transaction = transaction, + outputsBeingSpent = spentSpendingInfoDbs, + blockHashWithConfs = blockHashWithConfsOpt + ) + _ = if (outgoing.nonEmpty) { + logger.info( + s"Finished processing ${outgoing.length} spent outputs, it took=${TimeUtil.currentEpochMs - spentStart}ms" + ) + } + } yield { + ProcessTxResult(incoming, outgoing) } - actionF + + action } diff --git a/wallet/src/main/scala/org/bitcoins/wallet/internal/UtxoHandling.scala b/wallet/src/main/scala/org/bitcoins/wallet/internal/UtxoHandling.scala index 3498d6f463..15ab326dc6 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/internal/UtxoHandling.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/internal/UtxoHandling.scala @@ -24,6 +24,7 @@ import org.bitcoins.db.SafeDatabase import org.bitcoins.wallet.callback.WalletCallbacks import org.bitcoins.wallet.config.WalletAppConfig import org.bitcoins.wallet.models.{AddressDAO, SpendingInfoDAO, TransactionDAO} +import org.bitcoins.wallet.util.WalletUtil import slick.dbio.{DBIOAction, Effect, NoStream} import scala.concurrent.Future @@ -258,9 +259,8 @@ case class UtxoHandling( case (blockHashOpt, spendingInfoDbs) => blockHashOpt match { case Some(blockHash) => - chainQueryApi - .getNumberOfConfirmations(blockHash) - .map(confs => Some(BlockHashWithConfs(blockHash, confs))) + WalletUtil + .getBlockHashWithConfs(chainQueryApi, blockHash) .map(blockWithConfsOpt => (blockWithConfsOpt, spendingInfoDbs)) case None => Future.successful((None, spendingInfoDbs)) diff --git a/wallet/src/main/scala/org/bitcoins/wallet/util/WalletUtil.scala b/wallet/src/main/scala/org/bitcoins/wallet/util/WalletUtil.scala new file mode 100644 index 0000000000..e7dd66d9bf --- /dev/null +++ b/wallet/src/main/scala/org/bitcoins/wallet/util/WalletUtil.scala @@ -0,0 +1,30 @@ +package org.bitcoins.wallet.util + +import org.bitcoins.core.api.chain.ChainQueryApi +import org.bitcoins.core.util.BlockHashWithConfs +import org.bitcoins.crypto.DoubleSha256DigestBE + +import scala.concurrent.{ExecutionContext, Future} + +object WalletUtil { + + def getBlockHashWithConfs( + chainQueryApi: ChainQueryApi, + blockHashOpt: Option[DoubleSha256DigestBE])(implicit + ec: ExecutionContext): Future[Option[BlockHashWithConfs]] = { + blockHashOpt match { + case Some(blockHash) => + chainQueryApi + .getNumberOfConfirmations(blockHash) + .map(confsOpt => Some(BlockHashWithConfs(blockHash, confsOpt))) + case None => Future.successful(None) + } + } + + def getBlockHashWithConfs( + chainQueryApi: ChainQueryApi, + blockHash: DoubleSha256DigestBE)(implicit + ec: ExecutionContext): Future[Option[BlockHashWithConfs]] = { + getBlockHashWithConfs(chainQueryApi, Some(blockHash)) + } +}