@@ -116,17 +116,17 @@ class BitcoinCoreClient(val rpcClient: BitcoinJsonRPCClient, val lockUtxos: Bool
116116 * (not in the blockchain nor in the mempool) but could reappear later and be spendable at that point. If you want to
117117 * ensure that an output is not spendable anymore, you should use [[isTransactionOutputSpent ]].
118118 */
119- def isTransactionOutputSpendable (txid : TxId , outputIndex : Int , includeMempool : Boolean )(implicit ec : ExecutionContext ): Future [Boolean ] =
119+ def isTransactionOutputSpendable (outPoint : OutPoint , includeMempool : Boolean )(implicit ec : ExecutionContext ): Future [Boolean ] =
120120 for {
121- json <- rpcClient.invoke(" gettxout" , txid, outputIndex , includeMempool)
121+ json <- rpcClient.invoke(" gettxout" , outPoint. txid, outPoint.index , includeMempool)
122122 } yield json != JNull
123123
124124 /**
125125 * Return true if this output has already been spent by a confirmed transaction.
126126 * Note that a reorg may invalidate the result of this function and make a spent output spendable again.
127127 */
128- def isTransactionOutputSpent (txid : TxId , outputIndex : Int )(implicit ec : ExecutionContext ): Future [Boolean ] = {
129- getTxConfirmations(txid).flatMap {
128+ def isTransactionOutputSpent (outPoint : OutPoint )(implicit ec : ExecutionContext ): Future [Boolean ] = {
129+ getTxConfirmations(outPoint. txid).flatMap {
130130 case Some (confirmations) if confirmations > 0 =>
131131 // There is an important limitation when using isTransactionOutputSpendable: if it returns false, it can mean a
132132 // few different things:
@@ -137,7 +137,7 @@ class BitcoinCoreClient(val rpcClient: BitcoinJsonRPCClient, val lockUtxos: Bool
137137 // The only way to make sure that our output has been spent is to verify that it is coming from a confirmed
138138 // transaction and that it has been spent by another confirmed transaction. We want to ignore the mempool to
139139 // only consider spending transactions that have been confirmed.
140- isTransactionOutputSpendable(txid, outputIndex , includeMempool = false ).map(r => ! r)
140+ isTransactionOutputSpendable(outPoint , includeMempool = false ).map(r => ! r)
141141 case _ =>
142142 // If the output itself isn't in the blockchain, it cannot be spent by a confirmed transaction.
143143 Future .successful(false )
@@ -166,18 +166,18 @@ class BitcoinCoreClient(val rpcClient: BitcoinJsonRPCClient, val lockUtxos: Bool
166166 // themselves been double-spent, we will never be able to consider our transaction double-spent. With the
167167 // information we have, these unknown inputs could eventually reappear and the transaction could be broadcast
168168 // again.
169- Future .sequence(tx.txIn.map(txIn => isTransactionOutputSpent(txIn.outPoint.txid, txIn.outPoint.index.toInt ))).map(_.exists(_ == true ))
169+ Future .sequence(tx.txIn.map(txIn => isTransactionOutputSpent(txIn.outPoint))).map(_.exists(_ == true ))
170170 }
171171 } yield doubleSpent
172172
173173 /** Search for mempool transaction spending a given output. */
174- def lookForMempoolSpendingTx (txid : TxId , outputIndex : Int )(implicit ec : ExecutionContext ): Future [Transaction ] = {
175- rpcClient.invoke(" gettxspendingprevout" , Seq (OutpointArg (txid, outputIndex ))).collect {
174+ def lookForMempoolSpendingTx (outPoint : OutPoint )(implicit ec : ExecutionContext ): Future [Transaction ] = {
175+ rpcClient.invoke(" gettxspendingprevout" , Seq (OutpointArg (outPoint. txid, outPoint.index ))).collect {
176176 case JArray (results) => results.flatMap(result => (result \ " spendingtxid" ).extractOpt[String ].map(TxId .fromValidHex))
177177 }.flatMap { spendingTxIds =>
178178 spendingTxIds.headOption match {
179179 case Some (spendingTxId) => getTransaction(spendingTxId)
180- case None => Future .failed(new RuntimeException (s " mempool doesn't contain any transaction spending $txid : $outputIndex " ))
180+ case None => Future .failed(new RuntimeException (s " mempool doesn't contain any transaction spending $outPoint " ))
181181 }
182182 }
183183 }
@@ -188,23 +188,22 @@ class BitcoinCoreClient(val rpcClient: BitcoinJsonRPCClient, val lockUtxos: Bool
188188 * will have already claimed all possible outputs and there's nothing we can do about it.
189189 *
190190 * @param blockHash_opt hash of a block *after* the output has been spent. If not provided, we will use the blockchain tip.
191- * @param txid id of the transaction output that has been spent.
192- * @param outputIndex index of the transaction output that has been spent.
191+ * @param outPoint transaction output that has been spent.
193192 * @param limit maximum number of previous blocks to scan.
194193 * @return the transaction spending the given output.
195194 */
196- def lookForSpendingTx (blockHash_opt : Option [BlockHash ], txid : TxId , outputIndex : Int , limit : Int )(implicit ec : ExecutionContext ): Future [Transaction ] = {
195+ def lookForSpendingTx (blockHash_opt : Option [BlockHash ], outPoint : OutPoint , limit : Int )(implicit ec : ExecutionContext ): Future [Transaction ] = {
197196 for {
198197 blockId <- blockHash_opt match {
199198 case Some (blockHash) => Future .successful(BlockId (blockHash))
200199 // NB: bitcoind confusingly returns the blockId instead of the blockHash.
201200 case None => rpcClient.invoke(" getbestblockhash" ).collect { case JString (blockId) => BlockId (ByteVector32 .fromValidHex(blockId)) }
202201 }
203202 block <- getBlock(blockId)
204- res <- block.tx.asScala.find(tx => tx.txIn.asScala.exists(i => i.outPoint.txid == KotlinUtils .scala2kmp(txid) && i. outPoint.index == outputIndex )) match {
203+ res <- block.tx.asScala.find(tx => tx.txIn.asScala.exists(i => i.outPoint == KotlinUtils .scala2kmp(outPoint) )) match {
205204 case Some (tx) => Future .successful(KotlinUtils .kmp2scala(tx))
206- case None if limit > 0 => lookForSpendingTx(Some (KotlinUtils .kmp2scala(block.header.hashPreviousBlock)), txid, outputIndex , limit - 1 )
207- case None => Future .failed(new RuntimeException (s " couldn't find tx spending $txid : $outputIndex in the blockchain " ))
205+ case None if limit > 0 => lookForSpendingTx(Some (KotlinUtils .kmp2scala(block.header.hashPreviousBlock)), outPoint , limit - 1 )
206+ case None => Future .failed(new RuntimeException (s " couldn't find tx spending $outPoint in the blockchain " ))
208207 }
209208 } yield res
210209 }
@@ -755,12 +754,13 @@ class BitcoinCoreClient(val rpcClient: BitcoinJsonRPCClient, val lockUtxos: Bool
755754 TxId .fromValidHex(txs(txIndex).extract[String ])
756755 }.getOrElse(TxId (ByteVector32 .Zeroes )))
757756 tx <- getRawTransaction(txid)
758- unspent <- isTransactionOutputSpendable(txid, outputIndex, includeMempool = true )
757+ outPoint = OutPoint (txid, outputIndex)
758+ unspent <- isTransactionOutputSpendable(outPoint, includeMempool = true )
759759 fundingTxStatus <- if (unspent) {
760760 Future .successful(UtxoStatus .Unspent )
761761 } else {
762762 // if this returns true, it means that the spending tx is *not* in the blockchain
763- isTransactionOutputSpendable(txid, outputIndex , includeMempool = false ).map(res => UtxoStatus .Spent (spendingTxConfirmed = ! res))
763+ isTransactionOutputSpendable(outPoint , includeMempool = false ).map(res => UtxoStatus .Spent (spendingTxConfirmed = ! res))
764764 }
765765 } yield ValidateResult (c, Right ((Transaction .read(tx), fundingTxStatus)))
766766 } recover {
0 commit comments