From 547f6cd06e4a9d76ddfeeb7109712156a83b85e6 Mon Sep 17 00:00:00 2001 From: Doston Kamalov Date: Thu, 7 Dec 2023 10:35:11 +0500 Subject: [PATCH] AND-5492 Retrieve only the necessary inputs for the UTXO transaction. --- .../bitcoin/BitcoinTransactionBuilder.kt | 30 +++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/BitcoinTransactionBuilder.kt b/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/BitcoinTransactionBuilder.kt index cc243f9c3..c30496ac8 100644 --- a/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/BitcoinTransactionBuilder.kt +++ b/blockchain/src/main/java/com/tangem/blockchain/blockchains/bitcoin/BitcoinTransactionBuilder.kt @@ -26,7 +26,7 @@ import java.math.BigInteger open class BitcoinTransactionBuilder( private val walletPublicKey: ByteArray, blockchain: Blockchain, - walletAddresses: Set = emptySet() + walletAddresses: Set = emptySet(), ) { private val walletScripts = walletAddresses.filterIsInstance().map { it.script } @@ -51,9 +51,10 @@ open class BitcoinTransactionBuilder( return Result.Failure(BlockchainSdkError.CustomError("Unspent outputs are missing")) } - val change: BigDecimal = calculateChange(transactionData, unspentOutputs!!) + val outputsToSend = getOutputsToSend(unspentOutputs!!, transactionData) + val change: BigDecimal = calculateChange(transactionData, outputsToSend) transaction = - transactionData.toBitcoinJTransaction(networkParameters, unspentOutputs!!, change) + transactionData.toBitcoinJTransaction(networkParameters, outputsToSend, change) val hashesToSign = MutableList(transaction.inputs.size) { byteArrayOf() } for (input in transaction.inputs) { @@ -81,7 +82,7 @@ open class BitcoinTransactionBuilder( transaction.hashForWitnessSignature( index, scriptToSign, - Coin.parseCoin(unspentOutputs!![index].amount.toPlainString()), + Coin.parseCoin(outputsToSend[index].amount.toPlainString()), Transaction.SigHash.ALL, false ).bytes @@ -156,7 +157,7 @@ open class BitcoinTransactionBuilder( fun calculateChange( transactionData: TransactionData, - unspentOutputs: List + unspentOutputs: List, ): BigDecimal { val fullAmount = unspentOutputs.map { it.amount }.reduce { acc, number -> acc + number } return fullAmount - (transactionData.amount.value!! + (transactionData.fee?.amount?.value @@ -170,6 +171,23 @@ open class BitcoinTransactionBuilder( return TransactionSignature(r, canonicalS) } + private fun getOutputsToSend( + unspentOutputs: List, + transactionData: TransactionData, + ): List { + val outputs = mutableListOf() + val amount = transactionData.amount.value!! + transactionData.fee?.amount?.value!! + var sum = BigDecimal.ZERO + var i = 0 + while (sum <= amount && i < unspentOutputs.size) { + val output = unspentOutputs[i] + sum = sum.plus(output.amount) + outputs.add(output) + i++ + } + return outputs + } + private fun findSpendingScript(scriptPubKey: Script): Script { val scriptHash = ScriptPattern.extractHashFromP2SH(scriptPubKey) return when (scriptHash.size) { @@ -187,7 +205,7 @@ open class BitcoinTransactionBuilder( internal fun TransactionData.toBitcoinJTransaction( networkParameters: NetworkParameters?, unspentOutputs: List, - change: BigDecimal + change: BigDecimal, ): Transaction { val transaction = Transaction(networkParameters) for (utxo in unspentOutputs) {