mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-03-03 18:47:38 +01:00
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:
parent
2521c5da0e
commit
f75a52b521
19 changed files with 240 additions and 160 deletions
|
@ -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 =>
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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 ()
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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,22 +546,14 @@ 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
|
|
||||||
.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 {
|
for {
|
||||||
receivedSpendingInfoDbs <- receivedSpendingInfoDbsA
|
receivedSpendingInfoDbs <- receivedSpendingInfoDbsA
|
||||||
receivedStart = TimeUtil.currentEpochMs
|
receivedStart = TimeUtil.currentEpochMs
|
||||||
incoming <- processReceivedUtxosAction(
|
incoming <- processReceivedUtxosAction(
|
||||||
transaction = transaction,
|
transaction = transaction,
|
||||||
blockHashWithConfsOpt = confsOpt,
|
blockHashWithConfsOpt = blockHashWithConfsOpt,
|
||||||
spendingInfoDbs = receivedSpendingInfoDbs,
|
spendingInfoDbs = receivedSpendingInfoDbs,
|
||||||
newTags = newTags,
|
newTags = newTags,
|
||||||
relevantReceivedOutputs = relevantReceivedOutputs
|
relevantReceivedOutputs = relevantReceivedOutputs
|
||||||
|
@ -594,7 +571,7 @@ case class TransactionProcessing(
|
||||||
outgoing <- processSpentUtxosAction(
|
outgoing <- processSpentUtxosAction(
|
||||||
transaction = transaction,
|
transaction = transaction,
|
||||||
outputsBeingSpent = spentSpendingInfoDbs,
|
outputsBeingSpent = spentSpendingInfoDbs,
|
||||||
blockHashWithConfs = confsOpt
|
blockHashWithConfs = blockHashWithConfsOpt
|
||||||
)
|
)
|
||||||
_ = if (outgoing.nonEmpty) {
|
_ = if (outgoing.nonEmpty) {
|
||||||
logger.info(
|
logger.info(
|
||||||
|
@ -604,8 +581,8 @@ case class TransactionProcessing(
|
||||||
} yield {
|
} yield {
|
||||||
ProcessTxResult(incoming, outgoing)
|
ProcessTxResult(incoming, outgoing)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
actionF
|
action
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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))
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue