mirror of
https://github.com/lightninglabs/loop.git
synced 2026-08-13 12:33:03 +02:00
A group of inputs can be added by passing it in SweepRequest.Inputs field. All the inputs belong to the same swap and are added to the same batch.
794 lines
17 KiB
Go
794 lines
17 KiB
Go
package sweepbatcher
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/btcsuite/btcd/btcutil"
|
|
"github.com/btcsuite/btcd/chaincfg"
|
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
|
"github.com/btcsuite/btcd/wire"
|
|
"github.com/lightninglabs/loop/swap"
|
|
"github.com/lightningnetwork/lnd/input"
|
|
"github.com/lightningnetwork/lnd/lntypes"
|
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// Useful constants for tests.
|
|
const (
|
|
lowFeeRate = chainfee.FeePerKwFloor
|
|
highFeeRate = chainfee.SatPerKWeight(30000)
|
|
|
|
coopInputWeight = lntypes.WeightUnit(230)
|
|
nonCoopInputWeight = lntypes.WeightUnit(393)
|
|
nonCoopPenalty = nonCoopInputWeight - coopInputWeight
|
|
coopNewBatchWeight = lntypes.WeightUnit(444)
|
|
nonCoopNewBatchWeight = coopNewBatchWeight + nonCoopPenalty
|
|
|
|
// p2pkhDiscount is weight discount P2PKH output has over P2TR output.
|
|
p2pkhDiscount = lntypes.WeightUnit(
|
|
input.P2TROutputSize-input.P2PKHOutputSize,
|
|
) * 4
|
|
|
|
coopTwoSweepBatchWeight = coopNewBatchWeight + coopInputWeight
|
|
nonCoopTwoSweepBatchWeight = coopTwoSweepBatchWeight + 2*nonCoopPenalty
|
|
v2v3BatchWeight = nonCoopTwoSweepBatchWeight - 25
|
|
mixedTwoSweepBatchWeight = coopTwoSweepBatchWeight + nonCoopPenalty
|
|
)
|
|
|
|
// testHtlcV2SuccessEstimator adds weight of non-cooperative input to estimator
|
|
// using HTLC v2.
|
|
func testHtlcV2SuccessEstimator(estimator *input.TxWeightEstimator) error {
|
|
swapHash := lntypes.Hash{1, 1, 1}
|
|
htlc, err := swap.NewHtlcV2(
|
|
111, htlcKeys.SenderScriptKey, htlcKeys.ReceiverScriptKey,
|
|
swapHash, &chaincfg.RegressionNetParams,
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return htlc.AddSuccessToEstimator(estimator)
|
|
}
|
|
|
|
// testHtlcV3SuccessEstimator adds weight of non-cooperative input to estimator
|
|
// using HTLC v3.
|
|
func testHtlcV3SuccessEstimator(estimator *input.TxWeightEstimator) error {
|
|
swapHash := lntypes.Hash{1, 1, 1}
|
|
htlc, err := swap.NewHtlcV3(
|
|
input.MuSig2Version100RC2, 111,
|
|
htlcKeys.SenderInternalPubKey, htlcKeys.ReceiverInternalPubKey,
|
|
htlcKeys.SenderScriptKey, htlcKeys.ReceiverScriptKey, swapHash,
|
|
&chaincfg.RegressionNetParams,
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return htlc.AddSuccessToEstimator(estimator)
|
|
}
|
|
|
|
// TestEstimateSweepFeeIncrement tests that weight and fee estimations work
|
|
// correctly for a sweep and one sweep batch.
|
|
func TestEstimateSweepFeeIncrement(t *testing.T) {
|
|
// Useful variables reused in test cases.
|
|
se3 := testHtlcV3SuccessEstimator
|
|
trAddr := (*btcutil.AddressTaproot)(nil)
|
|
p2pkhAddr := (*btcutil.AddressPubKeyHash)(nil)
|
|
|
|
outpoint1 := wire.OutPoint{
|
|
Hash: chainhash.Hash{1, 1, 1},
|
|
Index: 1,
|
|
}
|
|
outpoint2 := wire.OutPoint{
|
|
Hash: chainhash.Hash{2, 2, 2},
|
|
Index: 2,
|
|
}
|
|
|
|
cases := []struct {
|
|
name string
|
|
sweeps []*sweep
|
|
wantSweepFeeDetails feeDetails
|
|
wantNewBatchFeeDetails feeDetails
|
|
}{
|
|
{
|
|
name: "regular",
|
|
sweeps: []*sweep{
|
|
{
|
|
minFeeRate: lowFeeRate,
|
|
htlcSuccessEstimator: se3,
|
|
},
|
|
},
|
|
wantSweepFeeDetails: feeDetails{
|
|
FeeRate: lowFeeRate,
|
|
Weight: coopInputWeight,
|
|
},
|
|
wantNewBatchFeeDetails: feeDetails{
|
|
FeeRate: lowFeeRate,
|
|
Weight: coopNewBatchWeight,
|
|
},
|
|
},
|
|
|
|
{
|
|
name: "high fee rate",
|
|
sweeps: []*sweep{
|
|
{
|
|
minFeeRate: highFeeRate,
|
|
htlcSuccessEstimator: se3,
|
|
},
|
|
},
|
|
wantSweepFeeDetails: feeDetails{
|
|
FeeRate: highFeeRate,
|
|
Weight: coopInputWeight,
|
|
},
|
|
wantNewBatchFeeDetails: feeDetails{
|
|
FeeRate: highFeeRate,
|
|
Weight: coopNewBatchWeight,
|
|
},
|
|
},
|
|
|
|
{
|
|
name: "isExternalAddr taproot",
|
|
sweeps: []*sweep{
|
|
{
|
|
minFeeRate: lowFeeRate,
|
|
htlcSuccessEstimator: se3,
|
|
isExternalAddr: true,
|
|
destAddr: trAddr,
|
|
},
|
|
},
|
|
wantSweepFeeDetails: feeDetails{
|
|
FeeRate: lowFeeRate,
|
|
Weight: coopInputWeight,
|
|
IsExternalAddr: true,
|
|
},
|
|
wantNewBatchFeeDetails: feeDetails{
|
|
FeeRate: lowFeeRate,
|
|
Weight: coopNewBatchWeight,
|
|
IsExternalAddr: true,
|
|
},
|
|
},
|
|
|
|
{
|
|
name: "isExternalAddr P2PKH",
|
|
sweeps: []*sweep{
|
|
{
|
|
minFeeRate: lowFeeRate,
|
|
htlcSuccessEstimator: se3,
|
|
isExternalAddr: true,
|
|
destAddr: p2pkhAddr,
|
|
},
|
|
},
|
|
wantSweepFeeDetails: feeDetails{
|
|
FeeRate: lowFeeRate,
|
|
Weight: coopInputWeight,
|
|
IsExternalAddr: true,
|
|
},
|
|
wantNewBatchFeeDetails: feeDetails{
|
|
FeeRate: lowFeeRate,
|
|
Weight: coopNewBatchWeight -
|
|
p2pkhDiscount,
|
|
IsExternalAddr: true,
|
|
},
|
|
},
|
|
|
|
{
|
|
name: "non-coop",
|
|
sweeps: []*sweep{
|
|
{
|
|
minFeeRate: lowFeeRate,
|
|
htlcSuccessEstimator: se3,
|
|
nonCoopHint: true,
|
|
},
|
|
},
|
|
wantSweepFeeDetails: feeDetails{
|
|
FeeRate: lowFeeRate,
|
|
Weight: nonCoopInputWeight,
|
|
},
|
|
wantNewBatchFeeDetails: feeDetails{
|
|
FeeRate: lowFeeRate,
|
|
Weight: nonCoopNewBatchWeight,
|
|
},
|
|
},
|
|
|
|
{
|
|
name: "coop-failed",
|
|
sweeps: []*sweep{
|
|
{
|
|
minFeeRate: lowFeeRate,
|
|
htlcSuccessEstimator: se3,
|
|
coopFailed: true,
|
|
},
|
|
},
|
|
wantSweepFeeDetails: feeDetails{
|
|
FeeRate: lowFeeRate,
|
|
Weight: nonCoopInputWeight,
|
|
},
|
|
wantNewBatchFeeDetails: feeDetails{
|
|
FeeRate: lowFeeRate,
|
|
Weight: nonCoopNewBatchWeight,
|
|
},
|
|
},
|
|
|
|
{
|
|
name: "two sweeps",
|
|
sweeps: []*sweep{
|
|
{
|
|
outpoint: outpoint1,
|
|
minFeeRate: lowFeeRate,
|
|
htlcSuccessEstimator: se3,
|
|
},
|
|
{
|
|
outpoint: outpoint2,
|
|
minFeeRate: highFeeRate,
|
|
htlcSuccessEstimator: se3,
|
|
},
|
|
},
|
|
wantSweepFeeDetails: feeDetails{
|
|
FeeRate: highFeeRate,
|
|
Weight: coopInputWeight * 2,
|
|
},
|
|
wantNewBatchFeeDetails: feeDetails{
|
|
FeeRate: highFeeRate,
|
|
Weight: coopNewBatchWeight + coopInputWeight,
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
gotSweepFeeDetails, gotNewBatchFeeDetails, err :=
|
|
estimateSweepFeeIncrement(tc.sweeps)
|
|
require.NoError(t, err)
|
|
require.Equal(
|
|
t, tc.wantSweepFeeDetails, gotSweepFeeDetails,
|
|
)
|
|
require.Equal(
|
|
t, tc.wantNewBatchFeeDetails,
|
|
gotNewBatchFeeDetails,
|
|
)
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestEstimateBatchWeight tests that weight and fee estimations work correctly
|
|
// for batches.
|
|
func TestEstimateBatchWeight(t *testing.T) {
|
|
// Useful variables reused in test cases.
|
|
outpoint1 := wire.OutPoint{
|
|
Hash: chainhash.Hash{1, 1, 1},
|
|
Index: 1,
|
|
}
|
|
outpoint2 := wire.OutPoint{
|
|
Hash: chainhash.Hash{2, 2, 2},
|
|
Index: 2,
|
|
}
|
|
se2 := testHtlcV2SuccessEstimator
|
|
se3 := testHtlcV3SuccessEstimator
|
|
trAddr := (*btcutil.AddressTaproot)(nil)
|
|
|
|
cases := []struct {
|
|
name string
|
|
batch *batch
|
|
wantBatchFeeDetails feeDetails
|
|
}{
|
|
{
|
|
name: "one sweep regular batch",
|
|
batch: &batch{
|
|
id: 1,
|
|
rbfCache: rbfCache{
|
|
FeeRate: lowFeeRate,
|
|
},
|
|
sweeps: map[wire.OutPoint]sweep{
|
|
outpoint1: {
|
|
htlcSuccessEstimator: se3,
|
|
},
|
|
},
|
|
},
|
|
wantBatchFeeDetails: feeDetails{
|
|
BatchId: 1,
|
|
FeeRate: lowFeeRate,
|
|
Weight: coopNewBatchWeight,
|
|
},
|
|
},
|
|
|
|
{
|
|
name: "two sweeps regular batch",
|
|
batch: &batch{
|
|
id: 1,
|
|
rbfCache: rbfCache{
|
|
FeeRate: lowFeeRate,
|
|
},
|
|
sweeps: map[wire.OutPoint]sweep{
|
|
outpoint1: {
|
|
htlcSuccessEstimator: se3,
|
|
},
|
|
outpoint2: {
|
|
htlcSuccessEstimator: se3,
|
|
},
|
|
},
|
|
},
|
|
wantBatchFeeDetails: feeDetails{
|
|
BatchId: 1,
|
|
FeeRate: lowFeeRate,
|
|
Weight: coopTwoSweepBatchWeight,
|
|
},
|
|
},
|
|
|
|
{
|
|
name: "v2 and v3 sweeps",
|
|
batch: &batch{
|
|
id: 1,
|
|
rbfCache: rbfCache{
|
|
FeeRate: lowFeeRate,
|
|
},
|
|
sweeps: map[wire.OutPoint]sweep{
|
|
outpoint1: {
|
|
htlcSuccessEstimator: se2,
|
|
},
|
|
outpoint2: {
|
|
htlcSuccessEstimator: se3,
|
|
},
|
|
},
|
|
},
|
|
wantBatchFeeDetails: feeDetails{
|
|
BatchId: 1,
|
|
FeeRate: lowFeeRate,
|
|
Weight: coopTwoSweepBatchWeight,
|
|
},
|
|
},
|
|
|
|
{
|
|
name: "v2 and v3 sweeps noncoop",
|
|
batch: &batch{
|
|
id: 1,
|
|
rbfCache: rbfCache{
|
|
FeeRate: lowFeeRate,
|
|
},
|
|
sweeps: map[wire.OutPoint]sweep{
|
|
outpoint1: {
|
|
htlcSuccessEstimator: se2,
|
|
nonCoopHint: true,
|
|
},
|
|
outpoint2: {
|
|
htlcSuccessEstimator: se3,
|
|
nonCoopHint: true,
|
|
},
|
|
},
|
|
},
|
|
wantBatchFeeDetails: feeDetails{
|
|
BatchId: 1,
|
|
FeeRate: lowFeeRate,
|
|
Weight: v2v3BatchWeight,
|
|
},
|
|
},
|
|
|
|
{
|
|
name: "high fee rate",
|
|
batch: &batch{
|
|
id: 1,
|
|
rbfCache: rbfCache{
|
|
FeeRate: highFeeRate,
|
|
},
|
|
sweeps: map[wire.OutPoint]sweep{
|
|
outpoint1: {
|
|
htlcSuccessEstimator: se3,
|
|
},
|
|
},
|
|
},
|
|
wantBatchFeeDetails: feeDetails{
|
|
BatchId: 1,
|
|
FeeRate: highFeeRate,
|
|
Weight: coopNewBatchWeight,
|
|
},
|
|
},
|
|
|
|
{
|
|
name: "non-coop",
|
|
batch: &batch{
|
|
id: 1,
|
|
rbfCache: rbfCache{
|
|
FeeRate: lowFeeRate,
|
|
},
|
|
sweeps: map[wire.OutPoint]sweep{
|
|
outpoint1: {
|
|
htlcSuccessEstimator: se3,
|
|
},
|
|
outpoint2: {
|
|
htlcSuccessEstimator: se3,
|
|
nonCoopHint: true,
|
|
},
|
|
},
|
|
},
|
|
wantBatchFeeDetails: feeDetails{
|
|
BatchId: 1,
|
|
FeeRate: lowFeeRate,
|
|
Weight: mixedTwoSweepBatchWeight,
|
|
},
|
|
},
|
|
|
|
{
|
|
name: "coop-failed",
|
|
batch: &batch{
|
|
id: 1,
|
|
rbfCache: rbfCache{
|
|
FeeRate: lowFeeRate,
|
|
},
|
|
sweeps: map[wire.OutPoint]sweep{
|
|
outpoint1: {
|
|
htlcSuccessEstimator: se3,
|
|
},
|
|
outpoint2: {
|
|
htlcSuccessEstimator: se3,
|
|
coopFailed: true,
|
|
},
|
|
},
|
|
},
|
|
wantBatchFeeDetails: feeDetails{
|
|
BatchId: 1,
|
|
FeeRate: lowFeeRate,
|
|
Weight: mixedTwoSweepBatchWeight,
|
|
},
|
|
},
|
|
|
|
{
|
|
name: "isExternalAddr",
|
|
batch: &batch{
|
|
id: 1,
|
|
rbfCache: rbfCache{
|
|
FeeRate: lowFeeRate,
|
|
},
|
|
sweeps: map[wire.OutPoint]sweep{
|
|
outpoint1: {
|
|
htlcSuccessEstimator: se3,
|
|
isExternalAddr: true,
|
|
destAddr: trAddr,
|
|
},
|
|
},
|
|
},
|
|
wantBatchFeeDetails: feeDetails{
|
|
BatchId: 1,
|
|
FeeRate: lowFeeRate,
|
|
Weight: coopNewBatchWeight,
|
|
IsExternalAddr: true,
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
gotBatchFeeDetails, err := estimateBatchWeight(tc.batch)
|
|
require.NoError(t, err)
|
|
require.Equal(
|
|
t, tc.wantBatchFeeDetails, gotBatchFeeDetails,
|
|
)
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestSelectBatches tests greedy batch selection algorithm.
|
|
func TestSelectBatches(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
batches []feeDetails
|
|
sweep, oneSweepBatch feeDetails
|
|
wantBestBatchesIds []int32
|
|
}{
|
|
{
|
|
name: "no existing batches",
|
|
batches: []feeDetails{},
|
|
sweep: feeDetails{
|
|
FeeRate: lowFeeRate,
|
|
Weight: coopInputWeight,
|
|
},
|
|
oneSweepBatch: feeDetails{
|
|
FeeRate: lowFeeRate,
|
|
Weight: coopNewBatchWeight,
|
|
},
|
|
wantBestBatchesIds: []int32{newBatchSignal},
|
|
},
|
|
|
|
{
|
|
name: "low fee sweep, low fee existing batch",
|
|
batches: []feeDetails{
|
|
{
|
|
BatchId: 1,
|
|
FeeRate: lowFeeRate,
|
|
Weight: coopNewBatchWeight,
|
|
},
|
|
},
|
|
sweep: feeDetails{
|
|
FeeRate: lowFeeRate,
|
|
Weight: coopInputWeight,
|
|
},
|
|
oneSweepBatch: feeDetails{
|
|
FeeRate: lowFeeRate,
|
|
Weight: coopNewBatchWeight,
|
|
},
|
|
wantBestBatchesIds: []int32{1, newBatchSignal},
|
|
},
|
|
|
|
{
|
|
name: "low fee sweep, high fee existing batch",
|
|
batches: []feeDetails{
|
|
{
|
|
BatchId: 1,
|
|
FeeRate: highFeeRate,
|
|
Weight: coopNewBatchWeight,
|
|
},
|
|
},
|
|
sweep: feeDetails{
|
|
FeeRate: lowFeeRate,
|
|
Weight: coopInputWeight,
|
|
},
|
|
oneSweepBatch: feeDetails{
|
|
FeeRate: lowFeeRate,
|
|
Weight: coopNewBatchWeight,
|
|
},
|
|
wantBestBatchesIds: []int32{newBatchSignal, 1},
|
|
},
|
|
|
|
{
|
|
name: "low fee sweep, low + high fee existing batches",
|
|
batches: []feeDetails{
|
|
{
|
|
BatchId: 1,
|
|
FeeRate: lowFeeRate,
|
|
Weight: coopNewBatchWeight,
|
|
},
|
|
{
|
|
BatchId: 2,
|
|
FeeRate: highFeeRate,
|
|
Weight: coopNewBatchWeight,
|
|
},
|
|
},
|
|
sweep: feeDetails{
|
|
FeeRate: lowFeeRate,
|
|
Weight: coopInputWeight,
|
|
},
|
|
oneSweepBatch: feeDetails{
|
|
FeeRate: lowFeeRate,
|
|
Weight: coopNewBatchWeight,
|
|
},
|
|
wantBestBatchesIds: []int32{1, newBatchSignal, 2},
|
|
},
|
|
|
|
{
|
|
name: "high fee sweep, low + high fee existing batches",
|
|
batches: []feeDetails{
|
|
{
|
|
BatchId: 1,
|
|
FeeRate: lowFeeRate,
|
|
Weight: coopNewBatchWeight,
|
|
},
|
|
{
|
|
BatchId: 2,
|
|
FeeRate: highFeeRate,
|
|
Weight: coopNewBatchWeight,
|
|
},
|
|
},
|
|
sweep: feeDetails{
|
|
FeeRate: highFeeRate,
|
|
Weight: coopInputWeight,
|
|
},
|
|
oneSweepBatch: feeDetails{
|
|
FeeRate: highFeeRate,
|
|
Weight: coopNewBatchWeight,
|
|
},
|
|
wantBestBatchesIds: []int32{2, newBatchSignal, 1},
|
|
},
|
|
|
|
{
|
|
name: "high fee noncoop sweep",
|
|
batches: []feeDetails{
|
|
{
|
|
BatchId: 1,
|
|
FeeRate: lowFeeRate,
|
|
Weight: coopNewBatchWeight,
|
|
},
|
|
{
|
|
BatchId: 2,
|
|
FeeRate: highFeeRate,
|
|
Weight: coopNewBatchWeight,
|
|
},
|
|
},
|
|
sweep: feeDetails{
|
|
FeeRate: highFeeRate,
|
|
Weight: nonCoopInputWeight,
|
|
},
|
|
oneSweepBatch: feeDetails{
|
|
FeeRate: highFeeRate,
|
|
Weight: nonCoopNewBatchWeight,
|
|
},
|
|
wantBestBatchesIds: []int32{2, newBatchSignal, 1},
|
|
},
|
|
|
|
{
|
|
name: "high fee noncoop sweep, large batches, mixed",
|
|
batches: []feeDetails{
|
|
{
|
|
BatchId: 1,
|
|
FeeRate: lowFeeRate,
|
|
Weight: 10000,
|
|
},
|
|
{
|
|
BatchId: 2,
|
|
FeeRate: highFeeRate,
|
|
Weight: 10000,
|
|
},
|
|
},
|
|
sweep: feeDetails{
|
|
FeeRate: highFeeRate,
|
|
Weight: nonCoopInputWeight,
|
|
},
|
|
oneSweepBatch: feeDetails{
|
|
FeeRate: highFeeRate,
|
|
Weight: nonCoopNewBatchWeight,
|
|
},
|
|
wantBestBatchesIds: []int32{2, newBatchSignal, 1},
|
|
},
|
|
|
|
{
|
|
name: "high fee noncoop sweep, high batch noncoop",
|
|
batches: []feeDetails{
|
|
{
|
|
BatchId: 1,
|
|
FeeRate: lowFeeRate,
|
|
Weight: coopNewBatchWeight,
|
|
},
|
|
{
|
|
BatchId: 2,
|
|
FeeRate: highFeeRate,
|
|
Weight: nonCoopNewBatchWeight,
|
|
},
|
|
},
|
|
sweep: feeDetails{
|
|
FeeRate: highFeeRate,
|
|
Weight: nonCoopInputWeight,
|
|
},
|
|
oneSweepBatch: feeDetails{
|
|
FeeRate: highFeeRate,
|
|
Weight: nonCoopNewBatchWeight,
|
|
},
|
|
wantBestBatchesIds: []int32{2, newBatchSignal, 1},
|
|
},
|
|
|
|
{
|
|
name: "low fee noncoop sweep",
|
|
batches: []feeDetails{
|
|
{
|
|
BatchId: 1,
|
|
FeeRate: lowFeeRate,
|
|
Weight: coopNewBatchWeight,
|
|
},
|
|
{
|
|
BatchId: 2,
|
|
FeeRate: highFeeRate,
|
|
Weight: coopNewBatchWeight,
|
|
},
|
|
},
|
|
sweep: feeDetails{
|
|
FeeRate: lowFeeRate,
|
|
Weight: nonCoopInputWeight,
|
|
},
|
|
oneSweepBatch: feeDetails{
|
|
FeeRate: lowFeeRate,
|
|
Weight: nonCoopNewBatchWeight,
|
|
},
|
|
wantBestBatchesIds: []int32{1, newBatchSignal, 2},
|
|
},
|
|
|
|
{
|
|
name: "low fee noncoop sweep, large batches, mixed",
|
|
batches: []feeDetails{
|
|
{
|
|
BatchId: 1,
|
|
FeeRate: lowFeeRate,
|
|
Weight: 10000,
|
|
},
|
|
{
|
|
BatchId: 2,
|
|
FeeRate: highFeeRate,
|
|
Weight: 10000,
|
|
},
|
|
},
|
|
sweep: feeDetails{
|
|
FeeRate: lowFeeRate,
|
|
Weight: nonCoopInputWeight,
|
|
},
|
|
oneSweepBatch: feeDetails{
|
|
FeeRate: lowFeeRate,
|
|
Weight: nonCoopNewBatchWeight,
|
|
},
|
|
wantBestBatchesIds: []int32{1, newBatchSignal, 2},
|
|
},
|
|
|
|
{
|
|
name: "low fee noncoop sweep, low batch noncoop",
|
|
batches: []feeDetails{
|
|
{
|
|
BatchId: 1,
|
|
FeeRate: lowFeeRate,
|
|
Weight: nonCoopNewBatchWeight,
|
|
},
|
|
{
|
|
BatchId: 2,
|
|
FeeRate: highFeeRate,
|
|
Weight: coopNewBatchWeight,
|
|
},
|
|
},
|
|
sweep: feeDetails{
|
|
FeeRate: lowFeeRate,
|
|
Weight: nonCoopInputWeight,
|
|
},
|
|
oneSweepBatch: feeDetails{
|
|
FeeRate: lowFeeRate,
|
|
Weight: nonCoopNewBatchWeight,
|
|
},
|
|
wantBestBatchesIds: []int32{1, newBatchSignal, 2},
|
|
},
|
|
|
|
{
|
|
name: "external address sweep",
|
|
batches: []feeDetails{
|
|
{
|
|
BatchId: 1,
|
|
FeeRate: highFeeRate,
|
|
Weight: coopNewBatchWeight,
|
|
},
|
|
{
|
|
BatchId: 2,
|
|
FeeRate: highFeeRate,
|
|
Weight: coopNewBatchWeight,
|
|
},
|
|
},
|
|
sweep: feeDetails{
|
|
FeeRate: highFeeRate,
|
|
Weight: coopInputWeight,
|
|
IsExternalAddr: true,
|
|
},
|
|
oneSweepBatch: feeDetails{
|
|
FeeRate: highFeeRate,
|
|
Weight: coopNewBatchWeight,
|
|
IsExternalAddr: true,
|
|
},
|
|
wantBestBatchesIds: []int32{newBatchSignal},
|
|
},
|
|
|
|
{
|
|
name: "external address batch",
|
|
batches: []feeDetails{
|
|
{
|
|
BatchId: 1,
|
|
FeeRate: highFeeRate - 1,
|
|
Weight: coopNewBatchWeight,
|
|
},
|
|
{
|
|
BatchId: 2,
|
|
FeeRate: highFeeRate,
|
|
Weight: coopNewBatchWeight,
|
|
IsExternalAddr: true,
|
|
},
|
|
},
|
|
sweep: feeDetails{
|
|
FeeRate: highFeeRate,
|
|
Weight: coopInputWeight,
|
|
},
|
|
oneSweepBatch: feeDetails{
|
|
FeeRate: highFeeRate,
|
|
Weight: coopNewBatchWeight,
|
|
},
|
|
wantBestBatchesIds: []int32{1, newBatchSignal},
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
gotBestBatchesIds, err := selectBatches(
|
|
tc.batches, tc.sweep, tc.oneSweepBatch,
|
|
)
|
|
require.NoError(t, err)
|
|
require.Equal(
|
|
t, tc.wantBestBatchesIds, gotBestBatchesIds,
|
|
)
|
|
})
|
|
}
|
|
}
|