Use SubtractFeeFromOutputsFinalizer when sending full utxos (#2072)

This commit is contained in:
Ben Carman 2020-10-01 17:32:24 -05:00 committed by GitHub
parent 4c202fd016
commit ed5228310b
4 changed files with 31 additions and 26 deletions

View File

@ -308,7 +308,7 @@ class RawTxSignerTest extends BitcoinSAsyncTest {
}
}
it should "dummy sign a mix of spks in a tx and then have fail verification" in {
it should "dummy sign a mix of spks in a tx and fill it with dummy signatures" in {
forAllAsync(CreditingTxGen.inputsAndOutputs(),
ScriptGenerators.scriptPubKey) {
case ((creditingTxsInfo, destinations), (changeSPK, _)) =>

View File

@ -250,7 +250,16 @@ case class AddWitnessDataFinalizer(inputInfos: Vector[InputInfo])
override def buildTx(txBuilderResult: RawTxBuilderResult)(implicit
ec: ExecutionContext): Future[Transaction] = {
val witnesses = inputInfos.map(InputInfo.getScriptWitness)
val result = txBuilderResult.toBaseTransaction
val sortedInputInfos = result.inputs
.flatMap(input => inputInfos.find(_.outPoint == input.previousOutput))
.toVector
require(sortedInputInfos.size == inputInfos.size, "Missing input infos")
val witnesses = sortedInputInfos.map(InputInfo.getScriptWitness)
TransactionWitness.fromWitOpt(witnesses) match {
case _: EmptyWitness =>
Future.successful(txBuilderResult.toBaseTransaction)

View File

@ -9,7 +9,6 @@ import org.bitcoins.core.script.control.OP_RETURN
import org.bitcoins.core.wallet.fee._
import org.bitcoins.core.wallet.utxo.TxoState
import org.bitcoins.crypto.CryptoUtil
import org.bitcoins.testkit.core.gen.{CurrencyUnitGenerator, FeeUnitGen}
import org.bitcoins.testkit.wallet.BitcoinSWalletTest
import org.bitcoins.testkit.wallet.BitcoinSWalletTest.RandomFeeProvider
import org.bitcoins.testkit.wallet.FundWalletUtil.FundedWallet

View File

@ -13,19 +13,14 @@ import org.bitcoins.core.crypto.ExtPublicKey
import org.bitcoins.core.currency._
import org.bitcoins.core.gcs.{GolombFilter, SimpleFilterMatcher}
import org.bitcoins.core.hd.{HDAccount, HDCoin, HDPurpose, HDPurposes}
import org.bitcoins.core.policy.Policy
import org.bitcoins.core.protocol.BitcoinAddress
import org.bitcoins.core.protocol.blockchain.ChainParams
import org.bitcoins.core.protocol.script.{EmptyScriptPubKey, ScriptPubKey}
import org.bitcoins.core.protocol.script.ScriptPubKey
import org.bitcoins.core.protocol.transaction._
import org.bitcoins.core.script.constant.ScriptConstant
import org.bitcoins.core.script.control.OP_RETURN
import org.bitcoins.core.util.{BitcoinScriptUtil, FutureUtil, HDUtil}
import org.bitcoins.core.wallet.builder.{
RawTxBuilderWithFinalizer,
RawTxSigner,
ShufflingNonInteractiveFinalizer
}
import org.bitcoins.core.wallet.builder._
import org.bitcoins.core.wallet.fee._
import org.bitcoins.core.wallet.keymanagement.{
KeyManagerParams,
@ -361,8 +356,8 @@ abstract class Wallet
/** Takes a [[RawTxBuilderWithFinalizer]] for a transaction to be sent, and completes it by:
* finalizing and signing the transaction, then correctly processing and logging it
*/
private def finishSend(
txBuilder: RawTxBuilderWithFinalizer[ShufflingNonInteractiveFinalizer],
private def finishSend[F <: RawTxFinalizer](
txBuilder: RawTxBuilderWithFinalizer[F],
utxoInfos: Vector[ScriptSignatureParams[InputInfo]],
sentAmount: CurrencyUnit,
feeRate: FeeUnit,
@ -416,28 +411,30 @@ abstract class Wallet
.findByOutPoint(utxo.outPoint)
.map(txDb => utxo.toUTXOInfo(keyManager, txDb.get.transaction)))
}
inputInfos = utxos.map(_.inputInfo)
utxoAmount = utxoDbs.map(_.output.value).sum
dummyOutput = TransactionOutput(utxoAmount, address.scriptPubKey)
inputs = InputUtil.calcSequenceForInputs(utxos)
dummyTx <-
TxUtil.buildDummyTx(utxos.map(_.inputInfo), Vector(dummyOutput))
txBuilder = RawTxBuilder() ++= inputs += dummyOutput
finalizer = SubtractFeeFromOutputsFinalizer(inputInfos, feeRate)
.andThen(ShuffleFinalizer)
.andThen(AddWitnessDataFinalizer(inputInfos))
fee = feeRate * dummyTx
amount = utxoAmount - fee
withFinalizer = txBuilder.setFinalizer(finalizer)
_ = require(amount > Policy.dustThreshold,
"Utxos are not large enough to send at this fee rate")
tmp <- withFinalizer.buildTx()
output = TransactionOutput(amount, address.scriptPubKey)
txBuilder = ShufflingNonInteractiveFinalizer.txBuilderFrom(
Vector(output),
utxos,
feeRate,
EmptyScriptPubKey // There will be no change
)
_ = require(
tmp.outputs.size == 1,
s"Created tx is not as expected, does not have 1 output, got $tmp")
tx <- finishSend(txBuilder, utxos, amount, feeRate, Vector.empty)
tx <- finishSend(withFinalizer,
utxos,
tmp.outputs.head.value,
feeRate,
Vector.empty)
} yield tx
}