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
This commit is contained in:
Chris Stewart 2024-10-28 12:52:53 -05:00 committed by GitHub
parent 2521c5da0e
commit f75a52b521
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 240 additions and 160 deletions

View file

@ -25,7 +25,7 @@ object CallbackUtil extends BitcoinSLogger {
val txSink = Sink.foreachAsync[Transaction](1) { case tx: Transaction => val txSink = Sink.foreachAsync[Transaction](1) { case tx: Transaction =>
logger.debug(s"Receiving transaction txid=${tx.txIdBE.hex} as a callback") logger.debug(s"Receiving transaction txid=${tx.txIdBE.hex} as a callback")
wallet.transactionProcessing wallet.transactionProcessing
.processTransaction(tx, blockHashOpt = None) .processTransaction(tx, blockHashWithConfsOpt = None)
.map(_ => ()) .map(_ => ())
} }
@ -109,7 +109,7 @@ object CallbackUtil extends BitcoinSLogger {
val txSink = Sink.foreachAsync[Transaction](1) { case tx: Transaction => val txSink = Sink.foreachAsync[Transaction](1) { case tx: Transaction =>
logger.debug(s"Receiving transaction txid=${tx.txIdBE.hex} as a callback") logger.debug(s"Receiving transaction txid=${tx.txIdBE.hex} as a callback")
wallet.transactionProcessing wallet.transactionProcessing
.processTransaction(tx, blockHashOpt = None) .processTransaction(tx, blockHashWithConfsOpt = None)
.map(_ => ()) .map(_ => ())
} }
val onTx: OnTxReceived = { tx => val onTx: OnTxReceived = { tx =>

View file

@ -4,6 +4,7 @@ import org.bitcoins.core.api.wallet.db.{SpendingInfoDb, TransactionDb}
import org.bitcoins.core.currency.CurrencyUnit import org.bitcoins.core.currency.CurrencyUnit
import org.bitcoins.core.protocol.blockchain.Block import org.bitcoins.core.protocol.blockchain.Block
import org.bitcoins.core.protocol.transaction.{OutputWithIndex, Transaction} 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.fee.FeeUnit
import org.bitcoins.core.wallet.utxo.AddressTag import org.bitcoins.core.wallet.utxo.AddressTag
import org.bitcoins.crypto.{DoubleSha256Digest, DoubleSha256DigestBE} import org.bitcoins.crypto.{DoubleSha256Digest, DoubleSha256DigestBE}
@ -26,7 +27,7 @@ trait TransactionProcessingApi {
def processTransaction( def processTransaction(
transaction: Transaction, transaction: Transaction,
blockHashOpt: Option[DoubleSha256DigestBE] blockHashWithConfsOpt: Option[BlockHashWithConfs]
): Future[Unit] ): Future[Unit]
/** Processes TXs originating from our wallet. This is called right after /** Processes TXs originating from our wallet. This is called right after
@ -37,7 +38,7 @@ trait TransactionProcessingApi {
feeRate: FeeUnit, feeRate: FeeUnit,
inputAmount: CurrencyUnit, inputAmount: CurrencyUnit,
sentAmount: CurrencyUnit, sentAmount: CurrencyUnit,
blockHashOpt: Option[DoubleSha256DigestBE], blockHashWithConfsOpt: Option[BlockHashWithConfs],
newTags: Vector[AddressTag] newTags: Vector[AddressTag]
): Future[ProcessTxResult] ): Future[ProcessTxResult]
@ -52,7 +53,7 @@ trait TransactionProcessingApi {
def processReceivedUtxos( def processReceivedUtxos(
tx: Transaction, tx: Transaction,
blockHashOpt: Option[DoubleSha256DigestBE], blockHashWithConfsOpt: Option[BlockHashWithConfs],
spendingInfoDbs: Vector[SpendingInfoDb], spendingInfoDbs: Vector[SpendingInfoDb],
newTags: Vector[AddressTag], newTags: Vector[AddressTag],
relevantReceivedOutputs: Vector[OutputWithIndex] relevantReceivedOutputs: Vector[OutputWithIndex]
@ -61,7 +62,7 @@ trait TransactionProcessingApi {
def processSpentUtxos( def processSpentUtxos(
transaction: Transaction, transaction: Transaction,
outputsBeingSpent: Vector[SpendingInfoDb], outputsBeingSpent: Vector[SpendingInfoDb],
blockHashOpt: Option[DoubleSha256DigestBE] blockHashWithConfsOpt: Option[BlockHashWithConfs]
): Future[Vector[SpendingInfoDb]] ): Future[Vector[SpendingInfoDb]]
def insertTransaction( def insertTransaction(

View file

@ -5,6 +5,7 @@ import org.bitcoins.core.protocol.dlc.models.{
DLCStatus, DLCStatus,
SingleContractInfo SingleContractInfo
} }
import org.bitcoins.core.util.BlockHashWithConfs
import org.bitcoins.dlc.wallet.callback.{DLCWalletCallbacks, OnDLCStateChange} import org.bitcoins.dlc.wallet.callback.{DLCWalletCallbacks, OnDLCStateChange}
import org.bitcoins.testkit.wallet.FundWalletUtil.FundedDLCWallet import org.bitcoins.testkit.wallet.FundWalletUtil.FundedDLCWallet
import org.bitcoins.testkit.wallet.{BitcoinSDualWalletTest, DLCWalletUtil} import org.bitcoins.testkit.wallet.{BitcoinSDualWalletTest, DLCWalletUtil}
@ -96,9 +97,11 @@ class DLCWalletCallbackTest extends BitcoinSDualWalletTest {
_ <- initF _ <- initF
contractId <- DLCWalletUtil.getContractId(wallets._1.wallet) contractId <- DLCWalletUtil.getContractId(wallets._1.wallet)
fundingTx <- walletA.getDLCFundingTx(contractId) fundingTx <- walletA.getDLCFundingTx(contractId)
blockHash = CryptoGenerators.doubleSha256DigestBE.sample.get
blockHashWithConfs = BlockHashWithConfs(blockHash, Some(1))
_ <- walletA.transactionProcessing.processTransaction( _ <- walletA.transactionProcessing.processTransaction(
transaction = fundingTx, transaction = fundingTx,
blockHashOpt = Some(CryptoGenerators.doubleSha256DigestBE.sample.get) blockHashWithConfsOpt = Some(blockHashWithConfs)
) )
sigs = { sigs = {
DLCWalletUtil.sampleContractInfo match { DLCWalletUtil.sampleContractInfo match {
@ -207,9 +210,11 @@ class DLCWalletCallbackTest extends BitcoinSDualWalletTest {
_ <- initF _ <- initF
contractId <- DLCWalletUtil.getContractId(wallets._1.wallet) contractId <- DLCWalletUtil.getContractId(wallets._1.wallet)
fundingTx <- walletA.getDLCFundingTx(contractId) fundingTx <- walletA.getDLCFundingTx(contractId)
blockHash = CryptoGenerators.doubleSha256DigestBE.sample.get
blockHashWithConfs = BlockHashWithConfs(blockHash, Some(1))
_ <- walletA.transactionProcessing.processTransaction( _ <- walletA.transactionProcessing.processTransaction(
transaction = fundingTx, transaction = fundingTx,
blockHashOpt = Some(CryptoGenerators.doubleSha256DigestBE.sample.get) blockHashWithConfsOpt = Some(blockHashWithConfs)
) )
transaction <- walletA.executeDLCRefund(contractId) transaction <- walletA.executeDLCRefund(contractId)
_ <- walletB.transactionProcessing.processTransaction(transaction, None) _ <- walletB.transactionProcessing.processTransaction(transaction, None)

View file

@ -1935,7 +1935,8 @@ case class DLCWallet(override val walletApi: Wallet)(implicit
_ <- updateClosingTxId(contractId, refundTx.txIdBE) _ <- updateClosingTxId(contractId, refundTx.txIdBE)
_ <- transactionProcessing.processTransaction(refundTx, _ <- transactionProcessing.processTransaction(refundTx,
blockHashOpt = None) blockHashWithConfsOpt =
None)
status <- findDLC(dlcDb.dlcId) status <- findDLC(dlcDb.dlcId)
_ <- dlcConfig.walletCallbacks.executeOnDLCStateChange(status.get) _ <- dlcConfig.walletCallbacks.executeOnDLCStateChange(status.get)
} yield refundTx } yield refundTx

View file

@ -22,7 +22,7 @@ import org.bitcoins.core.protocol.transaction.{
WitnessTransaction WitnessTransaction
} }
import org.bitcoins.core.psbt.InputPSBTRecord.PartialSignature 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.fee.FeeUnit
import org.bitcoins.core.wallet.utxo.{ import org.bitcoins.core.wallet.utxo.{
AddressTag, AddressTag,
@ -519,23 +519,25 @@ case class DLCTransactionProcessing(
override def processTransaction( override def processTransaction(
transaction: Transaction, transaction: Transaction,
blockHashOpt: Option[DoubleSha256DigestBE]): Future[Unit] = { blockHashWithConfsOpt: Option[BlockHashWithConfs]): Future[Unit] = {
txProcessing txProcessing
.processTransaction(transaction, blockHashOpt) .processTransaction(transaction, blockHashWithConfsOpt)
.flatMap(_ => processFundingTx(transaction, blockHashOpt)) .flatMap(_ =>
.flatMap(_ => processSettledDLCs(transaction, blockHashOpt)) processFundingTx(transaction, blockHashWithConfsOpt.map(_.blockHash)))
.flatMap(_ =>
processSettledDLCs(transaction, blockHashWithConfsOpt.map(_.blockHash)))
.map(_ => ()) .map(_ => ())
} }
override def processReceivedUtxos( override def processReceivedUtxos(
tx: Transaction, tx: Transaction,
blockHashOpt: Option[DoubleSha256DigestBE], blockHashWithConfsOpt: Option[BlockHashWithConfs],
spendingInfoDbs: Vector[SpendingInfoDb], spendingInfoDbs: Vector[SpendingInfoDb],
newTags: Vector[AddressTag], newTags: Vector[AddressTag],
relevantReceivedOutputs: Vector[OutputWithIndex]) relevantReceivedOutputs: Vector[OutputWithIndex])
: Future[Vector[SpendingInfoDb]] = { : Future[Vector[SpendingInfoDb]] = {
txProcessing.processReceivedUtxos(tx, txProcessing.processReceivedUtxos(tx,
blockHashOpt, blockHashWithConfsOpt,
spendingInfoDbs, spendingInfoDbs,
newTags, newTags,
relevantReceivedOutputs) relevantReceivedOutputs)
@ -544,9 +546,11 @@ case class DLCTransactionProcessing(
override def processSpentUtxos( override def processSpentUtxos(
transaction: Transaction, transaction: Transaction,
outputsBeingSpent: Vector[SpendingInfoDb], outputsBeingSpent: Vector[SpendingInfoDb],
blockHashOpt: Option[DoubleSha256DigestBE]) blockHashWithConfsOpt: Option[BlockHashWithConfs])
: Future[Vector[SpendingInfoDb]] = { : Future[Vector[SpendingInfoDb]] = {
txProcessing.processSpentUtxos(transaction, outputsBeingSpent, blockHashOpt) txProcessing.processSpentUtxos(transaction,
outputsBeingSpent,
blockHashWithConfsOpt)
} }
/** Processes TXs originating from our wallet. This is called right after /** Processes TXs originating from our wallet. This is called right after
@ -557,13 +561,13 @@ case class DLCTransactionProcessing(
feeRate: FeeUnit, feeRate: FeeUnit,
inputAmount: CurrencyUnit, inputAmount: CurrencyUnit,
sentAmount: CurrencyUnit, sentAmount: CurrencyUnit,
blockHashOpt: Option[DoubleSha256DigestBE], blockHashWithConfsOpt: Option[BlockHashWithConfs],
newTags: Vector[AddressTag]): Future[ProcessTxResult] = { newTags: Vector[AddressTag]): Future[ProcessTxResult] = {
txProcessing.processOurTransaction(transaction, txProcessing.processOurTransaction(transaction,
feeRate, feeRate,
inputAmount, inputAmount,
sentAmount, sentAmount,
blockHashOpt, blockHashWithConfsOpt,
newTags) newTags)
} }

View file

@ -64,7 +64,9 @@ import org.bitcoins.rpc.client.common.BitcoindRpcClient
import org.bitcoins.rpc.config._ import org.bitcoins.rpc.config._
import org.bitcoins.wallet.config.WalletAppConfig import org.bitcoins.wallet.config.WalletAppConfig
import org.bitcoins.core.api.wallet.WalletApi import org.bitcoins.core.api.wallet.WalletApi
import org.bitcoins.core.util.BlockHashWithConfs
import org.bitcoins.wallet.Wallet import org.bitcoins.wallet.Wallet
import org.bitcoins.wallet.util.WalletUtil
import com.typesafe.config.ConfigFactory import com.typesafe.config.ConfigFactory
import java.nio.file.Files import java.nio.file.Files
@ -157,12 +159,13 @@ val walletF: Future[WalletApi] = configF.flatMap { _ =>
// when this future completes, ww have sent a transaction // when this future completes, ww have sent a transaction
// from bitcoind to the Bitcoin-S wallet // from bitcoind to the Bitcoin-S wallet
val transactionF: Future[(Transaction, Option[DoubleSha256DigestBE])] = for { val transactionF: Future[(Transaction, Option[BlockHashWithConfs])] = for {
wallet <- walletF wallet <- walletF
address <- wallet.getNewAddress() address <- wallet.getNewAddress()
txid <- bitcoind.sendToAddress(address, 3.bitcoin) txid <- bitcoind.sendToAddress(address, 3.bitcoin)
transaction <- bitcoind.getRawTransaction(txid) 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 // when this future completes, we have processed
// the transaction from bitcoind, and we have // the transaction from bitcoind, and we have

View file

@ -5,7 +5,7 @@ import org.bitcoins.core.api.chain.ChainQueryApi.FilterResponse
import org.bitcoins.core.gcs.BlockFilter import org.bitcoins.core.gcs.BlockFilter
import org.bitcoins.core.protocol.BlockStamp import org.bitcoins.core.protocol.BlockStamp
import org.bitcoins.core.protocol.blockchain.RegTestNetChainParams 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 org.bitcoins.crypto.DoubleSha256DigestBE
import scala.concurrent.Future import scala.concurrent.Future
@ -19,6 +19,9 @@ object MockChainQueryApi extends ChainQueryApi {
"00000000496dcc754fabd97f3e2df0a7337eab417d75537fecf97a7ebb0e7c75" "00000000496dcc754fabd97f3e2df0a7337eab417d75537fecf97a7ebb0e7c75"
) )
val blockHashWithConfs: BlockHashWithConfs =
BlockHashWithConfs(testBlockHash, Some(6))
/** Gets the height of the given block */ /** Gets the height of the given block */
override def getBlockHeight( override def getBlockHeight(
blockHash: DoubleSha256DigestBE blockHash: DoubleSha256DigestBE
@ -41,7 +44,7 @@ object MockChainQueryApi extends ChainQueryApi {
blockHash: DoubleSha256DigestBE blockHash: DoubleSha256DigestBE
): Future[Option[Int]] = { ): Future[Option[Int]] = {
if (blockHash == testBlockHash) { if (blockHash == testBlockHash) {
Future.successful(Some(6)) Future.successful(blockHashWithConfs.confirmationsOpt)
} else FutureUtil.none } else FutureUtil.none
} }

View file

@ -25,6 +25,7 @@ import org.bitcoins.testkit.wallet.FundWalletUtil.{
import org.bitcoins.testkitcore.gen.TransactionGenerators import org.bitcoins.testkitcore.gen.TransactionGenerators
import org.bitcoins.testkitcore.util.TransactionTestUtil import org.bitcoins.testkitcore.util.TransactionTestUtil
import org.bitcoins.wallet.config.WalletAppConfig import org.bitcoins.wallet.config.WalletAppConfig
import org.bitcoins.wallet.util.WalletUtil
import scala.concurrent.{ExecutionContext, Future} import scala.concurrent.{ExecutionContext, Future}
@ -107,7 +108,10 @@ trait FundWalletUtil extends BitcoinSLogger {
addresses <- addressesF addresses <- addressesF
addressAmountMap = addresses.zip(amts).toMap addressAmountMap = addresses.zip(amts).toMap
(tx, blockHash) <- fundAddressesWithBitcoind(addressAmountMap, bitcoind) (tx, blockHash) <- fundAddressesWithBitcoind(addressAmountMap, bitcoind)
_ <- wallet.transactionProcessing.processTransaction(tx, Some(blockHash)) blockHashWithConfs <- WalletUtil.getBlockHashWithConfs(bitcoind,
blockHash)
_ <- wallet.transactionProcessing.processTransaction(tx,
blockHashWithConfs)
} yield (tx, blockHash) } yield (tx, blockHash)
txAndHashF.map(_ => wallet) txAndHashF.map(_ => wallet)

View file

@ -75,17 +75,18 @@ class ProcessTransactionTest extends BitcoinSWalletTest {
_ <- wallet.transactionProcessing.processTransaction( _ <- wallet.transactionProcessing.processTransaction(
tx, tx,
Some(MockChainQueryApi.testBlockHash) Some(MockChainQueryApi.blockHashWithConfs)
) )
newConfirmed <- wallet.getConfirmedBalance() newConfirmed <- wallet.getConfirmedBalance()
newUnconfirmed <- wallet.getUnconfirmedBalance() newUnconfirmed <- wallet.getUnconfirmedBalance()
utxosPostAdd <- wallet.utxoHandling.listUtxos() utxosPostAdd <- wallet.utxoHandling.listUtxos()
// repeating the action should not make a difference // repeating the action should not make a difference
_ <- checkUtxosAndBalance(wallet) { _ <- checkUtxosAndBalance(wallet) {
wallet.transactionProcessing.processTransaction( wallet.transactionProcessing.processTransaction(
tx, tx,
Some(MockChainQueryApi.testBlockHash)) Some(MockChainQueryApi.blockHashWithConfs))
} }
} yield { } yield {
val ourOutputs = val ourOutputs =
@ -196,7 +197,7 @@ class ProcessTransactionTest extends BitcoinSWalletTest {
) )
_ <- wallet.transactionProcessing.processTransaction( _ <- wallet.transactionProcessing.processTransaction(
transaction = rawTxHelper.signedTx, transaction = rawTxHelper.signedTx,
blockHashOpt = None blockHashWithConfsOpt = None
) )
balance <- wallet.getBalance() balance <- wallet.getBalance()
} yield assert(balance == amount) } yield assert(balance == amount)

View file

@ -11,6 +11,8 @@ import org.bitcoins.testkit.wallet.{
BitcoinSWalletTestCachedBitcoindNewest, BitcoinSWalletTestCachedBitcoindNewest,
WalletWithBitcoindRpc WalletWithBitcoindRpc
} }
import org.bitcoins.wallet.util.WalletUtil
import scala.concurrent.duration.DurationInt import scala.concurrent.duration.DurationInt
class RescanHandlingTest extends BitcoinSWalletTestCachedBitcoindNewest { class RescanHandlingTest extends BitcoinSWalletTestCachedBitcoindNewest {
@ -110,9 +112,12 @@ class RescanHandlingTest extends BitcoinSWalletTestCachedBitcoindNewest {
bitcoindAddr <- bitcoindAddrF bitcoindAddr <- bitcoindAddrF
blockHashes <- blockHashes <-
bitcoind.generateToAddress(blocks = numBlocks, address = bitcoindAddr) bitcoind.generateToAddress(blocks = numBlocks, address = bitcoindAddr)
blockHashWithConfs <- WalletUtil.getBlockHashWithConfs(
bitcoind,
blockHashes.headOption)
_ <- wallet.transactionProcessing.processTransaction( _ <- wallet.transactionProcessing.processTransaction(
transaction = tx, transaction = tx,
blockHashOpt = blockHashes.headOption blockHashWithConfsOpt = blockHashWithConfs
) )
balance <- wallet.getBalance() balance <- wallet.getBalance()
unconfirmedBalance <- wallet.getUnconfirmedBalance() unconfirmedBalance <- wallet.getUnconfirmedBalance()
@ -171,9 +176,12 @@ class RescanHandlingTest extends BitcoinSWalletTestCachedBitcoindNewest {
bitcoindAddr <- bitcoindAddrF bitcoindAddr <- bitcoindAddrF
blockHashes <- blockHashes <-
bitcoind.generateToAddress(blocks = numBlocks, address = bitcoindAddr) bitcoind.generateToAddress(blocks = numBlocks, address = bitcoindAddr)
blockHashWithConfs <- WalletUtil.getBlockHashWithConfs(
bitcoind,
blockHashes.headOption)
_ <- wallet.transactionProcessing.processTransaction( _ <- wallet.transactionProcessing.processTransaction(
transaction = tx, transaction = tx,
blockHashOpt = blockHashes.headOption blockHashWithConfsOpt = blockHashWithConfs
) )
balance <- wallet.getBalance() balance <- wallet.getBalance()
unconfirmedBalance <- wallet.getUnconfirmedBalance() unconfirmedBalance <- wallet.getUnconfirmedBalance()
@ -235,9 +243,12 @@ class RescanHandlingTest extends BitcoinSWalletTestCachedBitcoindNewest {
bitcoindAddr <- bitcoindAddrF bitcoindAddr <- bitcoindAddrF
blockHashes <- blockHashes <-
bitcoind.generateToAddress(blocks = numBlocks, address = bitcoindAddr) bitcoind.generateToAddress(blocks = numBlocks, address = bitcoindAddr)
blockHashWithConfs <- WalletUtil.getBlockHashWithConfs(
bitcoind,
blockHashes.headOption)
_ <- wallet.transactionProcessing.processTransaction( _ <- wallet.transactionProcessing.processTransaction(
transaction = tx, transaction = tx,
blockHashOpt = blockHashes.headOption blockHashWithConfsOpt = blockHashWithConfs
) )
balance <- wallet.getBalance() balance <- wallet.getBalance()
unconfirmedBalance <- wallet.getUnconfirmedBalance() unconfirmedBalance <- wallet.getUnconfirmedBalance()
@ -523,9 +534,12 @@ class RescanHandlingTest extends BitcoinSWalletTestCachedBitcoindNewest {
bitcoindAddr <- bitcoindAddrF bitcoindAddr <- bitcoindAddrF
blockHashes <- blockHashes <-
bitcoind.generateToAddress(blocks = numBlocks, address = bitcoindAddr) bitcoind.generateToAddress(blocks = numBlocks, address = bitcoindAddr)
blockHashWithConfs <- WalletUtil.getBlockHashWithConfs(
bitcoind,
blockHashes.headOption)
_ <- wallet.transactionProcessing.processTransaction( _ <- wallet.transactionProcessing.processTransaction(
transaction = tx, transaction = tx,
blockHashOpt = blockHashes.headOption blockHashWithConfsOpt = blockHashWithConfs
) )
balance <- wallet.getBalance() balance <- wallet.getBalance()
unconfirmedBalance <- wallet.getUnconfirmedBalance() unconfirmedBalance <- wallet.getUnconfirmedBalance()

View file

@ -4,21 +4,22 @@ import org.bitcoins.commons.util.BitcoinSLogger
import org.bitcoins.core.api.wallet.CoinSelectionAlgo import org.bitcoins.core.api.wallet.CoinSelectionAlgo
import org.bitcoins.core.api.wallet.db.SpendingInfoDb import org.bitcoins.core.api.wallet.db.SpendingInfoDb
import org.bitcoins.core.currency.{Bitcoins, Satoshis} 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.BitcoinAddress
import org.bitcoins.core.protocol.script._ import org.bitcoins.core.protocol.script.*
import org.bitcoins.core.protocol.transaction._ import org.bitcoins.core.protocol.transaction.*
import org.bitcoins.core.psbt.PSBT import org.bitcoins.core.psbt.PSBT
import org.bitcoins.core.wallet.builder.RawTxSigner import org.bitcoins.core.wallet.builder.RawTxSigner
import org.bitcoins.core.wallet.fee.{SatoshisPerByte, SatoshisPerVirtualByte} 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.core.wallet.utxo.TxoState.*
import org.bitcoins.crypto.{DoubleSha256DigestBE, ECPublicKey} import org.bitcoins.crypto.{DoubleSha256DigestBE, ECPublicKey}
import org.bitcoins.testkit.wallet.{ import org.bitcoins.testkit.wallet.{
BitcoinSWalletTestCachedBitcoindNewest, BitcoinSWalletTestCachedBitcoindNewest,
WalletWithBitcoindRpc WalletWithBitcoindRpc
} }
import org.bitcoins.wallet.models.SpendingInfoDAO import org.bitcoins.wallet.models.SpendingInfoDAO
import org.bitcoins.wallet.util.WalletUtil
import org.scalatest.{Assertion, FutureOutcome, Outcome} import org.scalatest.{Assertion, FutureOutcome, Outcome}
import scala.concurrent.Future 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 // Give tx a fake hash so it can appear as it's in a block
hash <- bitcoind.getBestBlockHash() hash <- bitcoind.getBestBlockHash()
_ <- wallet.transactionProcessing.processTransaction(tx, Some(hash)) blockHashWithConfs <- WalletUtil.getBlockHashWithConfs(bitcoind, hash)
_ <- wallet.transactionProcessing.processTransaction(tx,
blockHashWithConfs)
_ <- wallet.utxoHandling.updateUtxoPendingStates() _ <- wallet.utxoHandling.updateUtxoPendingStates()
pendingCoins <- wallet.utxoHandling.findOutputsBeingSpent(tx) 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 // Give tx a fake hash so it can appear as it's in a block
hash <- bitcoind.getBestBlockHash() hash <- bitcoind.getBestBlockHash()
_ <- wallet.transactionProcessing.processTransaction(tx, Some(hash)) blockHashWithConfs <- WalletUtil.getBlockHashWithConfs(bitcoind, hash)
_ <- wallet.transactionProcessing.processTransaction(tx,
blockHashWithConfs)
_ <- wallet.utxoHandling.updateUtxoPendingStates() _ <- wallet.utxoHandling.updateUtxoPendingStates()
pendingCoins <- wallet.utxoHandling.findOutputsBeingSpent(tx) pendingCoins <- wallet.utxoHandling.findOutputsBeingSpent(tx)
@ -390,7 +395,7 @@ class UTXOLifeCycleTest
feeRate = SatoshisPerByte(Satoshis(3)), feeRate = SatoshisPerByte(Satoshis(3)),
inputAmount = Satoshis(4000), inputAmount = Satoshis(4000),
sentAmount = Satoshis(3000), sentAmount = Satoshis(3000),
blockHashOpt = None, blockHashWithConfsOpt = None,
newTags = Vector.empty newTags = Vector.empty
) )
@ -419,7 +424,7 @@ class UTXOLifeCycleTest
feeRate = SatoshisPerByte(Satoshis(3)), feeRate = SatoshisPerByte(Satoshis(3)),
inputAmount = Satoshis(4000), inputAmount = Satoshis(4000),
sentAmount = Satoshis(3000), sentAmount = Satoshis(3000),
blockHashOpt = None, blockHashWithConfsOpt = None,
newTags = Vector.empty newTags = Vector.empty
) )
@ -431,7 +436,10 @@ class UTXOLifeCycleTest
hash <- bitcoind.getNewAddress hash <- bitcoind.getNewAddress
.flatMap(bitcoind.generateToAddress(1, _)) .flatMap(bitcoind.generateToAddress(1, _))
.map(_.head) .map(_.head)
_ <- wallet.transactionProcessing.processTransaction(tx, Some(hash)) blockHashWithConfsOpt <- WalletUtil.getBlockHashWithConfs(bitcoind, hash)
_ <- wallet.transactionProcessing.processTransaction(
tx,
blockHashWithConfsOpt)
pendingCoins <- pendingCoins <-
wallet.utxoHandling.findByScriptPubKey(addr.scriptPubKey) wallet.utxoHandling.findByScriptPubKey(addr.scriptPubKey)
@ -456,12 +464,14 @@ class UTXOLifeCycleTest
txId <- bitcoind.sendToAddress(addr, Satoshis(3000)) txId <- bitcoind.sendToAddress(addr, Satoshis(3000))
tx <- bitcoind.getRawTransactionRaw(txId) tx <- bitcoind.getRawTransactionRaw(txId)
blockHashWithConfsOpt <- WalletUtil.getBlockHashWithConfs(bitcoind,
Some(blockHash))
_ <- wallet.transactionProcessing.processOurTransaction( _ <- wallet.transactionProcessing.processOurTransaction(
transaction = tx, transaction = tx,
feeRate = SatoshisPerByte(Satoshis(3)), feeRate = SatoshisPerByte(Satoshis(3)),
inputAmount = Satoshis(4000), inputAmount = Satoshis(4000),
sentAmount = Satoshis(3000), sentAmount = Satoshis(3000),
blockHashOpt = Some(blockHash), // give fake hash blockHashWithConfsOpt = blockHashWithConfsOpt, // give fake hash
newTags = Vector.empty newTags = Vector.empty
) )

View file

@ -19,6 +19,7 @@ import org.bitcoins.wallet.models.{
IncomingTransactionDAO, IncomingTransactionDAO,
OutgoingTransactionDAO OutgoingTransactionDAO
} }
import org.bitcoins.wallet.util.WalletUtil
import org.scalatest.{FutureOutcome, Outcome} import org.scalatest.{FutureOutcome, Outcome}
import scala.concurrent.Future import scala.concurrent.Future
@ -92,7 +93,11 @@ class WalletIntegrationTest extends BitcoinSWalletTestCachedBitcoindNewest {
rawTx <- bitcoind.getRawTransaction(txId) rawTx <- bitcoind.getRawTransaction(txId)
// after this, tx should be confirmed // 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 wallet.utxoHandling
.listUtxos() .listUtxos()
@ -176,8 +181,11 @@ class WalletIntegrationTest extends BitcoinSWalletTestCachedBitcoindNewest {
txId <- bitcoind.sendToAddress(addr, valueFromBitcoind) txId <- bitcoind.sendToAddress(addr, valueFromBitcoind)
rawTx <- bitcoind.getRawTransaction(txId) rawTx <- bitcoind.getRawTransaction(txId)
_ <- bitcoind.generate(6) _ <- bitcoind.generate(6)
_ <- wallet.transactionProcessing.processTransaction(rawTx.hex, blockHashWithConfsOpt <- WalletUtil.getBlockHashWithConfs(bitcoind,
rawTx.blockhash) rawTx.blockhash)
_ <- wallet.transactionProcessing.processTransaction(
rawTx.hex,
blockHashWithConfsOpt)
// Verify we funded the wallet // Verify we funded the wallet
balance <- wallet.getBalance() balance <- wallet.getBalance()
@ -243,8 +251,11 @@ class WalletIntegrationTest extends BitcoinSWalletTestCachedBitcoindNewest {
txId <- bitcoind.sendToAddress(addr, valueFromBitcoind) txId <- bitcoind.sendToAddress(addr, valueFromBitcoind)
_ <- bitcoind.generate(6) _ <- bitcoind.generate(6)
rawTx <- bitcoind.getRawTransaction(txId) rawTx <- bitcoind.getRawTransaction(txId)
_ <- wallet.transactionProcessing.processTransaction(rawTx.hex, blockHashWithConfsOpt <- WalletUtil.getBlockHashWithConfs(bitcoind,
rawTx.blockhash) rawTx.blockhash)
_ <- wallet.transactionProcessing.processTransaction(
rawTx.hex,
blockHashWithConfsOpt)
// Verify we funded the wallet // Verify we funded the wallet
balance <- wallet.getBalance() balance <- wallet.getBalance()
@ -262,8 +273,11 @@ class WalletIntegrationTest extends BitcoinSWalletTestCachedBitcoindNewest {
_ <- bitcoind.generate(1) _ <- bitcoind.generate(1)
rawTx1 <- bitcoind.getRawTransaction(rbf.txIdBE) rawTx1 <- bitcoind.getRawTransaction(rbf.txIdBE)
_ = require(rawTx1.blockhash.isDefined) _ = require(rawTx1.blockhash.isDefined)
_ <- wallet.transactionProcessing.processTransaction(rbf, blockHashWithConfsOpt <- WalletUtil.getBlockHashWithConfs(bitcoind,
rawTx1.blockhash) rawTx.blockhash)
_ <- wallet.transactionProcessing.processTransaction(
rbf,
blockHashWithConfsOpt)
// fail to RBF confirmed tx // fail to RBF confirmed tx
res <- recoverToSucceededIf[IllegalArgumentException] { res <- recoverToSucceededIf[IllegalArgumentException] {
@ -283,8 +297,11 @@ class WalletIntegrationTest extends BitcoinSWalletTestCachedBitcoindNewest {
txId <- bitcoind.sendToAddress(addr, valueFromBitcoind) txId <- bitcoind.sendToAddress(addr, valueFromBitcoind)
rawTx <- bitcoind.getRawTransaction(txId) rawTx <- bitcoind.getRawTransaction(txId)
_ <- bitcoind.generate(6) _ <- bitcoind.generate(6)
_ <- wallet.transactionProcessing.processTransaction(rawTx.hex, blockHashWithConfsOpt <- WalletUtil.getBlockHashWithConfs(bitcoind,
rawTx.blockhash) rawTx.blockhash)
_ <- wallet.transactionProcessing.processTransaction(
rawTx.hex,
blockHashWithConfsOpt)
// Verify we funded the wallet // Verify we funded the wallet
balance <- wallet.getBalance() balance <- wallet.getBalance()

View file

@ -19,6 +19,7 @@ import org.bitcoins.testkitcore.Implicits.GeneratorOps
import org.bitcoins.testkitcore.gen.FeeUnitGen import org.bitcoins.testkitcore.gen.FeeUnitGen
import org.bitcoins.wallet.config.WalletAppConfig import org.bitcoins.wallet.config.WalletAppConfig
import org.bitcoins.wallet.models.{OutgoingTransactionDAO, SpendingInfoDAO} import org.bitcoins.wallet.models.{OutgoingTransactionDAO, SpendingInfoDAO}
import org.bitcoins.wallet.util.WalletUtil
import org.scalatest.{Assertion, FutureOutcome} import org.scalatest.{Assertion, FutureOutcome}
import scodec.bits.ByteVector import scodec.bits.ByteVector
@ -379,9 +380,12 @@ class WalletSendingTest extends BitcoinSWalletTest {
tx <- wallet.sendFundsHandling.sendToAddress(testAddress, tx <- wallet.sendFundsHandling.sendToAddress(testAddress,
amountToSend, amountToSend,
feeRate) feeRate)
blockHashWithConfsOpt <- WalletUtil.getBlockHashWithConfs(
chainQueryApi,
Some(DoubleSha256DigestBE.empty))
_ <- wallet.transactionProcessing.processTransaction( _ <- wallet.transactionProcessing.processTransaction(
tx, tx,
Some(DoubleSha256DigestBE.empty)) blockHashWithConfsOpt)
res <- recoverToSucceededIf[IllegalArgumentException] { res <- recoverToSucceededIf[IllegalArgumentException] {
wallet.sendFundsHandling.bumpFeeRBF(tx.txIdBE, newFeeRate) wallet.sendFundsHandling.bumpFeeRBF(tx.txIdBE, newFeeRate)
@ -470,9 +474,12 @@ class WalletSendingTest extends BitcoinSWalletTest {
tx <- wallet.sendFundsHandling.sendToAddress(testAddress, tx <- wallet.sendFundsHandling.sendToAddress(testAddress,
amountToSend, amountToSend,
feeRate) feeRate)
blockHashWithConfsOpt <- WalletUtil.getBlockHashWithConfs(
chainQueryApi,
Some(DoubleSha256DigestBE.empty))
_ <- wallet.transactionProcessing.processTransaction( _ <- wallet.transactionProcessing.processTransaction(
tx, tx,
Some(DoubleSha256DigestBE.empty)) blockHashWithConfsOpt)
res <- recoverToSucceededIf[IllegalArgumentException] { res <- recoverToSucceededIf[IllegalArgumentException] {
wallet.sendFundsHandling.bumpFeeCPFP(tx.txIdBE, feeRate) wallet.sendFundsHandling.bumpFeeCPFP(tx.txIdBE, feeRate)

View file

@ -254,9 +254,9 @@ class WalletUnitTest extends BitcoinSWalletTest {
spk = addr.scriptPubKey spk = addr.scriptPubKey
_ = assert(spk == P2PKHScriptPubKey(walletKey)) _ = assert(spk == P2PKHScriptPubKey(walletKey))
dummyPrevTx = dummyTx(spk = spk) dummyPrevTx = dummyTx(spk = spk)
_ <- wallet.transactionProcessing.processTransaction(dummyPrevTx, _ <- wallet.transactionProcessing.processTransaction(
blockHashOpt = dummyPrevTx,
None) blockHashWithConfsOpt = None)
psbt = dummyPSBT(prevTxId = dummyPrevTx.txId) psbt = dummyPSBT(prevTxId = dummyPrevTx.txId)
@ -280,9 +280,9 @@ class WalletUnitTest extends BitcoinSWalletTest {
spk = addr.scriptPubKey spk = addr.scriptPubKey
_ = assert(spk == P2SHScriptPubKey(P2WPKHWitnessSPKV0(walletKey))) _ = assert(spk == P2SHScriptPubKey(P2WPKHWitnessSPKV0(walletKey)))
dummyPrevTx = dummyTx(spk = spk) dummyPrevTx = dummyTx(spk = spk)
_ <- wallet.transactionProcessing.processTransaction(dummyPrevTx, _ <- wallet.transactionProcessing.processTransaction(
blockHashOpt = dummyPrevTx,
None) blockHashWithConfsOpt = None)
psbt = dummyPSBT(prevTxId = dummyPrevTx.txId) psbt = dummyPSBT(prevTxId = dummyPrevTx.txId)
@ -306,9 +306,9 @@ class WalletUnitTest extends BitcoinSWalletTest {
spk = addr.scriptPubKey spk = addr.scriptPubKey
_ = assert(spk == P2WPKHWitnessSPKV0(walletKey)) _ = assert(spk == P2WPKHWitnessSPKV0(walletKey))
dummyPrevTx = dummyTx(spk = spk) dummyPrevTx = dummyTx(spk = spk)
_ <- wallet.transactionProcessing.processTransaction(dummyPrevTx, _ <- wallet.transactionProcessing.processTransaction(
blockHashOpt = dummyPrevTx,
None) blockHashWithConfsOpt = None)
psbt = dummyPSBT(prevTxId = dummyPrevTx.txId) psbt = dummyPSBT(prevTxId = dummyPrevTx.txId)
.addUTXOToInput(dummyPrevTx, 0) .addUTXOToInput(dummyPrevTx, 0)
@ -339,12 +339,14 @@ class WalletUnitTest extends BitcoinSWalletTest {
spk = addr.scriptPubKey spk = addr.scriptPubKey
_ = assert(spk == P2WPKHWitnessSPKV0(walletKey)) _ = assert(spk == P2WPKHWitnessSPKV0(walletKey))
dummyPrevTx = dummyTx(spk = spk) dummyPrevTx = dummyTx(spk = spk)
_ <- wallet.transactionProcessing.processTransaction(dummyPrevTx, _ <- wallet.transactionProcessing.processTransaction(
blockHashOpt = None) dummyPrevTx,
blockHashWithConfsOpt = None)
dummyPrevTx1 = dummyTx(prevTxId = dummyPrevTx.txId, spk = spk) dummyPrevTx1 = dummyTx(prevTxId = dummyPrevTx.txId, spk = spk)
_ <- wallet.transactionProcessing.processTransaction(dummyPrevTx1, _ <- wallet.transactionProcessing.processTransaction(
blockHashOpt = None) dummyPrevTx1,
blockHashWithConfsOpt = None)
toBroadcast <- wallet.sendFundsHandling.getTransactionsToBroadcast toBroadcast <- wallet.sendFundsHandling.getTransactionsToBroadcast
} yield assert(toBroadcast.map(_.txIdBE) == Vector(dummyPrevTx1.txIdBE)) } yield assert(toBroadcast.map(_.txIdBE) == Vector(dummyPrevTx1.txIdBE))

View file

@ -232,7 +232,8 @@ case class Wallet(
for { for {
_ <- nodeApi.broadcastTransaction(transaction) _ <- nodeApi.broadcastTransaction(transaction)
_ <- transactionProcessing.processTransaction(transaction, _ <- transactionProcessing.processTransaction(transaction,
blockHashOpt = None) blockHashWithConfsOpt =
None)
_ <- walletCallbacks.executeOnTransactionBroadcast(transaction) _ <- walletCallbacks.executeOnTransactionBroadcast(transaction)
} yield () } yield ()

View file

@ -604,7 +604,7 @@ case class SendFundsHandlingHandling(
feeRate = feeRate, feeRate = feeRate,
inputAmount = creditingAmount, inputAmount = creditingAmount,
sentAmount = sentAmount, sentAmount = sentAmount,
blockHashOpt = None, blockHashWithConfsOpt = None,
newTags = newTags newTags = newTags
) )
} yield { } yield {

View file

@ -38,6 +38,7 @@ import org.bitcoins.wallet.models.{
WalletDAOs, WalletDAOs,
WalletStateDescriptorDAO WalletStateDescriptorDAO
} }
import org.bitcoins.wallet.util.WalletUtil
import slick.dbio.{DBIOAction, Effect, NoStream} import slick.dbio.{DBIOAction, Effect, NoStream}
import scala.collection.mutable import scala.collection.mutable
@ -82,13 +83,13 @@ case class TransactionProcessing(
/** @inheritdoc */ /** @inheritdoc */
override def processTransaction( override def processTransaction(
transaction: Transaction, transaction: Transaction,
blockHashOpt: Option[DoubleSha256DigestBE] blockHashWithConfsOpt: Option[BlockHashWithConfs]
): Future[Unit] = { ): Future[Unit] = {
for { for {
relevantReceivedOutputs <- getRelevantOutputs(transaction) relevantReceivedOutputs <- getRelevantOutputs(transaction)
action <- processTransactionImpl( action = processTransactionImpl(
transaction = transaction, transaction = transaction,
blockHashOpt = blockHashOpt, blockHashWithConfsOpt = blockHashWithConfsOpt,
newTags = Vector.empty, newTags = Vector.empty,
receivedSpendingInfoDbsOpt = None, receivedSpendingInfoDbsOpt = None,
spentSpendingInfoDbsOpt = None, spentSpendingInfoDbsOpt = None,
@ -187,7 +188,9 @@ case class TransactionProcessing(
val spentSpendingInfoDbsF = val spentSpendingInfoDbsF =
spendingInfoDAO.findOutputsBeingSpent(block.transactions.toVector) 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 // fetch all outputs we may have received in this block in advance
// as an optimization // as an optimization
@ -201,6 +204,7 @@ case class TransactionProcessing(
spentSpendingInfoDbs <- spentSpendingInfoDbsF spentSpendingInfoDbs <- spentSpendingInfoDbsF
relevantReceivedOutputsForBlock <- relevantReceivedOutputsForBlock <-
relevantReceivedOutputsForBlockF relevantReceivedOutputsForBlockF
blockHashWithConfsOpt <- blockHashWithConfsOptF
} yield { } yield {
// we need to keep a cache of spentSpendingInfoDb // we need to keep a cache of spentSpendingInfoDb
// for the case where we receive & then spend that // for the case where we receive & then spend that
@ -215,10 +219,10 @@ case class TransactionProcessing(
_ <- walletF _ <- walletF
relevantReceivedOutputsForTx = relevantReceivedOutputsForBlock relevantReceivedOutputsForTx = relevantReceivedOutputsForBlock
.getOrElse(transaction.txIdBE, Vector.empty) .getOrElse(transaction.txIdBE, Vector.empty)
action <- action =
processTransactionImpl( processTransactionImpl(
transaction = transaction, transaction = transaction,
blockHashOpt = blockHashOpt, blockHashWithConfsOpt = blockHashWithConfsOpt,
newTags = Vector.empty, newTags = Vector.empty,
receivedSpendingInfoDbsOpt = receivedSpendingInfoDbsOpt, receivedSpendingInfoDbsOpt = receivedSpendingInfoDbsOpt,
spentSpendingInfoDbsOpt = cachedSpentOpt, spentSpendingInfoDbsOpt = cachedSpentOpt,
@ -314,12 +318,12 @@ case class TransactionProcessing(
feeRate: FeeUnit, feeRate: FeeUnit,
inputAmount: CurrencyUnit, inputAmount: CurrencyUnit,
sentAmount: CurrencyUnit, sentAmount: CurrencyUnit,
blockHashOpt: Option[DoubleSha256DigestBE], blockHashWithConfsOpt: Option[BlockHashWithConfs],
newTags: Vector[AddressTag] newTags: Vector[AddressTag]
): Future[ProcessTxResult] = { ): Future[ProcessTxResult] = {
logger.info( logger.info(
s"Processing TX from our wallet, transaction=${transaction.txIdBE.hex} with blockHash=${blockHashOpt s"Processing TX from our wallet, transaction=${transaction.txIdBE.hex} with blockHash=${blockHashWithConfsOpt
.map(_.hex)}" .map(_.blockHash.hex)}"
) )
val relevantOutputsF = getRelevantOutputs(transaction) val relevantOutputsF = getRelevantOutputs(transaction)
for { for {
@ -329,12 +333,12 @@ case class TransactionProcessing(
feeRate, feeRate,
inputAmount, inputAmount,
sentAmount, sentAmount,
blockHashOpt blockHashWithConfsOpt.map(_.blockHash)
) )
relevantOutputs <- relevantOutputsF relevantOutputs <- relevantOutputsF
action <- processTransactionImpl( action = processTransactionImpl(
transaction = txDb.transaction, transaction = txDb.transaction,
blockHashOpt = blockHashOpt, blockHashWithConfsOpt = blockHashWithConfsOpt,
newTags = newTags, newTags = newTags,
receivedSpendingInfoDbsOpt = None, receivedSpendingInfoDbsOpt = None,
spentSpendingInfoDbsOpt = None, spentSpendingInfoDbsOpt = None,
@ -444,48 +448,30 @@ case class TransactionProcessing(
*/ */
override def processReceivedUtxos( override def processReceivedUtxos(
transaction: Transaction, transaction: Transaction,
blockHashOpt: Option[DoubleSha256DigestBE], blockHashWithConfsOpt: Option[BlockHashWithConfs],
spendingInfoDbs: Vector[SpendingInfoDb], spendingInfoDbs: Vector[SpendingInfoDb],
newTags: Vector[AddressTag], newTags: Vector[AddressTag],
relevantReceivedOutputs: Vector[OutputWithIndex] relevantReceivedOutputs: Vector[OutputWithIndex]
): Future[Vector[SpendingInfoDb]] = { ): 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 => val action = processReceivedUtxosAction(transaction,
processReceivedUtxosAction(transaction, blockHashWithConfsOpt,
confsOpt, spendingInfoDbs,
spendingInfoDbs, newTags,
newTags, relevantReceivedOutputs)
relevantReceivedOutputs) safeDatabase.run(action)
}
actionF.flatMap(a => safeDatabase.run(a))
} }
override def processSpentUtxos( override def processSpentUtxos(
transaction: Transaction, transaction: Transaction,
outputsBeingSpent: Vector[SpendingInfoDb], outputsBeingSpent: Vector[SpendingInfoDb],
blockHashOpt: Option[DoubleSha256DigestBE] blockHashWithConfsOpt: Option[BlockHashWithConfs]
): Future[Vector[SpendingInfoDb]] = { ): Future[Vector[SpendingInfoDb]] = {
val blockHashWithConfsF: Future[Option[BlockHashWithConfs]] = val action = processSpentUtxosAction(transaction,
blockHashOpt match { outputsBeingSpent,
case Some(blockHash) => blockHashWithConfsOpt)
chainQueryApi
.getNumberOfConfirmations(blockHash)
.map(BlockHashWithConfs(blockHash, _))
.map(Some.apply)
case None => Future.successful(None)
}
val actionF = blockHashWithConfsF.map { confsOpt =>
processSpentUtxosAction(transaction, outputsBeingSpent, confsOpt)
}
actionF.flatMap(safeDatabase.run) safeDatabase.run(action)
} }
/** Searches for outputs on the given transaction that are being spent from /** Searches for outputs on the given transaction that are being spent from
@ -521,17 +507,16 @@ case class TransactionProcessing(
*/ */
private[internal] def processTransactionImpl( private[internal] def processTransactionImpl(
transaction: Transaction, transaction: Transaction,
blockHashOpt: Option[DoubleSha256DigestBE], blockHashWithConfsOpt: Option[BlockHashWithConfs],
newTags: Vector[AddressTag], newTags: Vector[AddressTag],
receivedSpendingInfoDbsOpt: Option[Vector[SpendingInfoDb]], receivedSpendingInfoDbsOpt: Option[Vector[SpendingInfoDb]],
spentSpendingInfoDbsOpt: Option[Vector[SpendingInfoDb]], spentSpendingInfoDbsOpt: Option[Vector[SpendingInfoDb]],
relevantReceivedOutputs: Vector[OutputWithIndex] relevantReceivedOutputs: Vector[OutputWithIndex]
): Future[ ): DBIOAction[ProcessTxResult, NoStream, Effect.Read & Effect.Write] = {
DBIOAction[ProcessTxResult, NoStream, Effect.Read & Effect.Write]] = {
logger.debug( logger.debug(
s"Processing transaction=${transaction.txIdBE.hex} with blockHash=${blockHashOpt s"Processing transaction=${transaction.txIdBE.hex} with blockHash=${blockHashWithConfsOpt
.map(_.hex)}" .map(_.blockHash.hex)}"
) )
val receivedSpendingInfoDbsA val receivedSpendingInfoDbsA
: DBIOAction[Vector[SpendingInfoDb], NoStream, Effect.Read] = { : DBIOAction[Vector[SpendingInfoDb], NoStream, Effect.Read] = {
@ -561,51 +546,43 @@ case class TransactionProcessing(
spendingInfoDAO.findOutputsBeingSpentAction(Vector(transaction)) spendingInfoDAO.findOutputsBeingSpentAction(Vector(transaction))
} }
} }
val confsOptF: Future[Option[BlockHashWithConfs]] = blockHashOpt match { val action
case Some(blockHash) => : DBIOAction[ProcessTxResult, NoStream, Effect.Write & Effect.Read] =
chainQueryApi for {
.getNumberOfConfirmations(blockHash) receivedSpendingInfoDbs <- receivedSpendingInfoDbsA
.map(confsOpt => Some(BlockHashWithConfs(blockHash, confsOpt))) receivedStart = TimeUtil.currentEpochMs
case None => Future.successful(None) incoming <- processReceivedUtxosAction(
} transaction = transaction,
val actionF: Future[ blockHashWithConfsOpt = blockHashWithConfsOpt,
DBIOAction[ProcessTxResult, NoStream, Effect.Write & Effect.Read]] = spendingInfoDbs = receivedSpendingInfoDbs,
confsOptF.map { confsOpt => newTags = newTags,
for { relevantReceivedOutputs = relevantReceivedOutputs
receivedSpendingInfoDbs <- receivedSpendingInfoDbsA )
receivedStart = TimeUtil.currentEpochMs _ = if (incoming.nonEmpty) {
incoming <- processReceivedUtxosAction( logger.info(
transaction = transaction, s"Finished processing ${incoming.length} received outputs, balance=${incoming
blockHashWithConfsOpt = confsOpt, .map(_.output.value)
spendingInfoDbs = receivedSpendingInfoDbs, .sum} it took=${TimeUtil.currentEpochMs - receivedStart}ms"
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"
)
}
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
} }

View file

@ -24,6 +24,7 @@ import org.bitcoins.db.SafeDatabase
import org.bitcoins.wallet.callback.WalletCallbacks import org.bitcoins.wallet.callback.WalletCallbacks
import org.bitcoins.wallet.config.WalletAppConfig import org.bitcoins.wallet.config.WalletAppConfig
import org.bitcoins.wallet.models.{AddressDAO, SpendingInfoDAO, TransactionDAO} import org.bitcoins.wallet.models.{AddressDAO, SpendingInfoDAO, TransactionDAO}
import org.bitcoins.wallet.util.WalletUtil
import slick.dbio.{DBIOAction, Effect, NoStream} import slick.dbio.{DBIOAction, Effect, NoStream}
import scala.concurrent.Future import scala.concurrent.Future
@ -258,9 +259,8 @@ case class UtxoHandling(
case (blockHashOpt, spendingInfoDbs) => case (blockHashOpt, spendingInfoDbs) =>
blockHashOpt match { blockHashOpt match {
case Some(blockHash) => case Some(blockHash) =>
chainQueryApi WalletUtil
.getNumberOfConfirmations(blockHash) .getBlockHashWithConfs(chainQueryApi, blockHash)
.map(confs => Some(BlockHashWithConfs(blockHash, confs)))
.map(blockWithConfsOpt => (blockWithConfsOpt, spendingInfoDbs)) .map(blockWithConfsOpt => (blockWithConfsOpt, spendingInfoDbs))
case None => case None =>
Future.successful((None, spendingInfoDbs)) Future.successful((None, spendingInfoDbs))

View file

@ -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))
}
}