sweep: add required TxOuts to sweep tx

Now that inputs might have accompanied outputs to be added to the sweep
tx, we add them to the sweep transaction first, and account for it when
calculating the change amount.
This commit is contained in:
Johan T. Halseth 2020-11-16 12:52:22 +01:00
parent 7f9df26efd
commit 616503de3e
No known key found for this signature in database
GPG Key ID: 15BAADA29DA20D26

@ -147,15 +147,23 @@ func createSweepTx(inputs []input.Input, outputPkScript []byte,
// Track whether any of the inputs require a certain locktime. // Track whether any of the inputs require a certain locktime.
locktime := int32(-1) locktime := int32(-1)
// Sum up the total value contained in the inputs, and add all inputs // We start by adding all inputs that commit to an output. We do this
// to the sweep transaction. Ensure that for each csvInput, we set the // since the input and output index must stay the same for the
// sequence number properly. // signatures to be valid.
var totalSum btcutil.Amount var (
totalInput btcutil.Amount
requiredOutput btcutil.Amount
)
for _, o := range inputs { for _, o := range inputs {
if o.RequiredTxOut() == nil {
continue
}
sweepTx.AddTxIn(&wire.TxIn{ sweepTx.AddTxIn(&wire.TxIn{
PreviousOutPoint: *o.OutPoint(), PreviousOutPoint: *o.OutPoint(),
Sequence: o.BlocksToMaturity(), Sequence: o.BlocksToMaturity(),
}) })
sweepTx.AddTxOut(o.RequiredTxOut())
if lt, ok := o.RequiredLockTime(); ok { if lt, ok := o.RequiredLockTime(); ok {
// If another input commits to a different locktime, // If another input commits to a different locktime,
@ -167,18 +175,44 @@ func createSweepTx(inputs []input.Input, outputPkScript []byte,
locktime = int32(lt) locktime = int32(lt)
} }
totalSum += btcutil.Amount(o.SignDesc().Output.Value) totalInput += btcutil.Amount(o.SignDesc().Output.Value)
requiredOutput += btcutil.Amount(o.RequiredTxOut().Value)
} }
// Sweep as much possible, after subtracting txn fees. // Sum up the value contained in the remaining inputs, and add them to
sweepAmt := totalSum - txFee // the sweep transaction.
for _, o := range inputs {
if o.RequiredTxOut() != nil {
continue
}
sweepTx.AddTxIn(&wire.TxIn{
PreviousOutPoint: *o.OutPoint(),
Sequence: o.BlocksToMaturity(),
})
if lt, ok := o.RequiredLockTime(); ok {
if locktime != -1 && locktime != int32(lt) {
return nil, fmt.Errorf("incompatible locktime")
}
locktime = int32(lt)
}
totalInput += btcutil.Amount(o.SignDesc().Output.Value)
}
// The value remaining after the required output and fees, go to
// change. Not that this fee is what we would have to pay in case the
// sweep tx has a change output.
changeAmt := totalInput - requiredOutput - txFee
// The txn will sweep the amount after fees to the pkscript generated // The txn will sweep the amount after fees to the pkscript generated
// above. // above.
if sweepAmt >= dustLimit { if changeAmt >= dustLimit {
sweepTx.AddTxOut(&wire.TxOut{ sweepTx.AddTxOut(&wire.TxOut{
PkScript: outputPkScript, PkScript: outputPkScript,
Value: int64(sweepAmt), Value: int64(changeAmt),
}) })
} }
@ -255,7 +289,12 @@ func getWeightEstimate(inputs []input.Input, feeRate chainfee.SatPerKWeight) (
weightEstimate := newWeightEstimator(feeRate) weightEstimate := newWeightEstimator(feeRate)
// Our sweep transaction will pay to a single segwit p2wkh address, // Our sweep transaction will pay to a single segwit p2wkh address,
// ensure it contributes to our weight estimate. // ensure it contributes to our weight estimate. If the inputs we add
// have required TxOuts, then this will be our change address. Note
// that if we have required TxOuts, we might end up creating a sweep tx
// without a change output. It is okay to add the change output to the
// weight estimate regardless, since the estimated fee will just be
// subtracted from this already dust output, and trimmed.
weightEstimate.addP2WKHOutput() weightEstimate.addP2WKHOutput()
// For each output, use its witness type to determine the estimate // For each output, use its witness type to determine the estimate
@ -274,6 +313,12 @@ func getWeightEstimate(inputs []input.Input, feeRate chainfee.SatPerKWeight) (
continue continue
} }
// If this input comes with a committed output, add that as
// well.
if inp.RequiredTxOut() != nil {
weightEstimate.addOutput(inp.RequiredTxOut())
}
sweepInputs = append(sweepInputs, inp) sweepInputs = append(sweepInputs, inp)
} }