Skip to content

Commit dd85a61

Browse files
authored
Merge pull request #976 from hieblmi/batcher-change-outputs
sweepbatcher: batch change outputs
2 parents 340681f + d00b78e commit dd85a61

13 files changed

+1688
-163
lines changed

loopout_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,7 @@ func testCustomSweepConfTarget(t *testing.T) {
280280
// yields a much higher fee rate.
281281
ctx.Lnd.SetFeeEstimate(testReq.SweepConfTarget, 250)
282282
ctx.Lnd.SetFeeEstimate(DefaultSweepConfTarget, 10000)
283+
ctx.Lnd.SetMinRelayFee(250)
283284

284285
cfg := newSwapConfig(
285286
&lnd.LndServices, loopdb.NewStoreMock(t), server, nil,

sweepbatcher/greedy_batch_selection.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,23 @@ func estimateBatchWeight(batch *batch) (feeDetails, error) {
210210
err)
211211
}
212212

213+
// Add change output weights. Change outputs with identical pkscript
214+
// will be consolidated into a single output.
215+
changeOutputs := make(map[string]struct{})
216+
for _, s := range batch.sweeps {
217+
if s.change == nil {
218+
continue
219+
}
220+
221+
pkScriptString := string(s.change.PkScript)
222+
if _, has := changeOutputs[pkScriptString]; has {
223+
continue
224+
}
225+
226+
weight.AddOutput(s.change.PkScript)
227+
changeOutputs[pkScriptString] = struct{}{}
228+
}
229+
213230
// Add inputs.
214231
for _, sweep := range batch.sweeps {
215232
if sweep.nonCoopHint || sweep.coopFailed {

sweepbatcher/greedy_batch_selection_test.go

Lines changed: 112 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"github.com/btcsuite/btcd/btcutil"
77
"github.com/btcsuite/btcd/chaincfg"
88
"github.com/btcsuite/btcd/chaincfg/chainhash"
9+
"github.com/btcsuite/btcd/txscript"
910
"github.com/btcsuite/btcd/wire"
1011
"github.com/lightninglabs/loop/swap"
1112
"github.com/lightningnetwork/lnd/input"
@@ -16,24 +17,29 @@ import (
1617

1718
// Useful constants for tests.
1819
const (
19-
lowFeeRate = chainfee.FeePerKwFloor
20-
highFeeRate = chainfee.SatPerKWeight(30000)
20+
lowFeeRate = chainfee.FeePerKwFloor
21+
mediumFeeRate = lowFeeRate + 200
22+
highFeeRate = chainfee.SatPerKWeight(30000)
2123

2224
coopInputWeight = lntypes.WeightUnit(230)
25+
batchOutputWeight = lntypes.WeightUnit(343)
2326
nonCoopInputWeight = lntypes.WeightUnit(393)
2427
nonCoopPenalty = nonCoopInputWeight - coopInputWeight
2528
coopNewBatchWeight = lntypes.WeightUnit(444)
2629
nonCoopNewBatchWeight = coopNewBatchWeight + nonCoopPenalty
30+
changeOutputWeight = lntypes.WeightUnit(input.P2TROutputSize)
2731

2832
// p2pkhDiscount is weight discount P2PKH output has over P2TR output.
2933
p2pkhDiscount = lntypes.WeightUnit(
3034
input.P2TROutputSize-input.P2PKHOutputSize,
3135
) * 4
3236

33-
coopTwoSweepBatchWeight = coopNewBatchWeight + coopInputWeight
34-
nonCoopTwoSweepBatchWeight = coopTwoSweepBatchWeight + 2*nonCoopPenalty
35-
v2v3BatchWeight = nonCoopTwoSweepBatchWeight - 25
36-
mixedTwoSweepBatchWeight = coopTwoSweepBatchWeight + nonCoopPenalty
37+
coopTwoSweepBatchWeight = coopNewBatchWeight + coopInputWeight
38+
coopSingleSweepChangeBatchWeight = coopInputWeight + batchOutputWeight + changeOutputWeight
39+
coopDoubleSweepChangeBatchWeight = 2*coopInputWeight + batchOutputWeight + changeOutputWeight
40+
nonCoopTwoSweepBatchWeight = coopTwoSweepBatchWeight + 2*nonCoopPenalty
41+
v2v3BatchWeight = nonCoopTwoSweepBatchWeight - 25
42+
mixedTwoSweepBatchWeight = coopTwoSweepBatchWeight + nonCoopPenalty
3743
)
3844

3945
// testHtlcV2SuccessEstimator adds weight of non-cooperative input to estimator
@@ -265,6 +271,13 @@ func TestEstimateBatchWeight(t *testing.T) {
265271
se3 := testHtlcV3SuccessEstimator
266272
trAddr := (*btcutil.AddressTaproot)(nil)
267273

274+
changeAddr := "bc1pdx9ggvtjjcpaqfqk375qhdmzx9xu8dcu7w94lqfcxhh0rj" +
275+
"lwyyeq5ryn6r"
276+
changeAddress, err := btcutil.DecodeAddress(changeAddr, nil)
277+
require.NoError(t, err)
278+
changePkscript, err := txscript.PayToAddrScript(changeAddress)
279+
require.NoError(t, err)
280+
268281
cases := []struct {
269282
name string
270283
batch *batch
@@ -290,6 +303,58 @@ func TestEstimateBatchWeight(t *testing.T) {
290303
},
291304
},
292305

306+
{
307+
name: "one sweep regular batch with change",
308+
batch: &batch{
309+
id: 1,
310+
rbfCache: rbfCache{
311+
FeeRate: lowFeeRate,
312+
},
313+
sweeps: map[wire.OutPoint]sweep{
314+
outpoint1: {
315+
htlcSuccessEstimator: se3,
316+
change: &wire.TxOut{
317+
PkScript: changePkscript,
318+
},
319+
},
320+
},
321+
},
322+
wantBatchFeeDetails: feeDetails{
323+
BatchId: 1,
324+
FeeRate: lowFeeRate,
325+
Weight: coopSingleSweepChangeBatchWeight,
326+
},
327+
},
328+
329+
{
330+
name: "two sweeps regular batch with identical change",
331+
batch: &batch{
332+
id: 1,
333+
rbfCache: rbfCache{
334+
FeeRate: lowFeeRate,
335+
},
336+
sweeps: map[wire.OutPoint]sweep{
337+
outpoint1: {
338+
htlcSuccessEstimator: se3,
339+
change: &wire.TxOut{
340+
PkScript: changePkscript,
341+
},
342+
},
343+
outpoint2: {
344+
htlcSuccessEstimator: se3,
345+
change: &wire.TxOut{
346+
PkScript: changePkscript,
347+
},
348+
},
349+
},
350+
},
351+
wantBatchFeeDetails: feeDetails{
352+
BatchId: 1,
353+
FeeRate: lowFeeRate,
354+
Weight: coopDoubleSweepChangeBatchWeight,
355+
},
356+
},
357+
293358
{
294359
name: "two sweeps regular batch",
295360
batch: &batch{
@@ -778,6 +843,47 @@ func TestSelectBatches(t *testing.T) {
778843
},
779844
wantBestBatchesIds: []int32{1, newBatchSignal},
780845
},
846+
847+
{
848+
name: "low fee change sweep, placed in new batch",
849+
batches: []feeDetails{
850+
{
851+
BatchId: 1,
852+
FeeRate: mediumFeeRate,
853+
Weight: coopNewBatchWeight,
854+
},
855+
},
856+
sweep: feeDetails{
857+
FeeRate: lowFeeRate,
858+
Weight: coopInputWeight + changeOutputWeight,
859+
},
860+
oneSweepBatch: feeDetails{
861+
FeeRate: lowFeeRate,
862+
Weight: coopNewBatchWeight,
863+
},
864+
wantBestBatchesIds: []int32{newBatchSignal, 1},
865+
},
866+
867+
{
868+
name: "low fee sweep without change, placed in " +
869+
"existing batch",
870+
batches: []feeDetails{
871+
{
872+
BatchId: 1,
873+
FeeRate: mediumFeeRate,
874+
Weight: coopNewBatchWeight,
875+
},
876+
},
877+
sweep: feeDetails{
878+
FeeRate: lowFeeRate,
879+
Weight: coopInputWeight,
880+
},
881+
oneSweepBatch: feeDetails{
882+
FeeRate: lowFeeRate,
883+
Weight: coopNewBatchWeight,
884+
},
885+
wantBestBatchesIds: []int32{1, newBatchSignal},
886+
},
781887
}
782888

783889
for _, tc := range cases {

0 commit comments

Comments
 (0)