diff --git a/sweep/sweeper_test.go b/sweep/sweeper_test.go index f18cc4917..ee143e3d3 100644 --- a/sweep/sweeper_test.go +++ b/sweep/sweeper_test.go @@ -1693,78 +1693,6 @@ func TestPendingInputs(t *testing.T) { ctx.finish(1) } -// TestBumpFeeRBF ensures that the UtxoSweeper can properly handle a fee bump -// request for an input it is currently attempting to sweep. When sweeping the -// input with the higher fee rate, a replacement transaction is created. -func TestBumpFeeRBF(t *testing.T) { - t.Skip("fix me") - - ctx := createSweeperTestContext(t) - - lowFeePref := FeeEstimateInfo{ConfTarget: 144} - lowFeeRate := chainfee.FeePerKwFloor - ctx.estimator.blocksToFee[lowFeePref.ConfTarget] = lowFeeRate - - // We'll first try to bump the fee of an output currently unknown to the - // UtxoSweeper. Doing so should result in a lnwallet.ErrNotMine error. - _, err := ctx.sweeper.UpdateParams( - wire.OutPoint{}, ParamsUpdate{Fee: lowFeePref}, - ) - if err != lnwallet.ErrNotMine { - t.Fatalf("expected error lnwallet.ErrNotMine, got \"%v\"", err) - } - - // We'll then attempt to sweep an input, which we'll use to bump its fee - // later on. - input := createTestInput( - btcutil.SatoshiPerBitcoin, input.CommitmentTimeLock, - ) - sweepResult, err := ctx.sweeper.SweepInput( - &input, Params{Fee: lowFeePref}, - ) - if err != nil { - t.Fatal(err) - } - - // Generate the same type of change script used so we can have accurate - // weight estimation. - changePk, err := ctx.sweeper.cfg.GenSweepScript() - require.NoError(t, err) - - // Ensure that a transaction is broadcast with the lower fee preference. - lowFeeTx := ctx.receiveTx() - assertTxFeeRate(t, &lowFeeTx, lowFeeRate, changePk, &input) - - // We'll then attempt to bump its fee rate. - highFeePref := FeeEstimateInfo{ConfTarget: 6} - highFeeRate := DefaultMaxFeeRate.FeePerKWeight() - ctx.estimator.blocksToFee[highFeePref.ConfTarget] = highFeeRate - - // We should expect to see an error if a fee preference isn't provided. - _, err = ctx.sweeper.UpdateParams(*input.OutPoint(), ParamsUpdate{ - Fee: &FeeEstimateInfo{}, - }) - if err != ErrNoFeePreference { - t.Fatalf("expected ErrNoFeePreference, got %v", err) - } - - bumpResult, err := ctx.sweeper.UpdateParams( - *input.OutPoint(), ParamsUpdate{Fee: highFeePref}, - ) - require.NoError(t, err, "unable to bump input's fee") - - // A higher fee rate transaction should be immediately broadcast. - highFeeTx := ctx.receiveTx() - assertTxFeeRate(t, &highFeeTx, highFeeRate, changePk, &input) - - // We'll finish our test by mining the sweep transaction. - ctx.backend.mine() - ctx.expectResult(sweepResult, nil) - ctx.expectResult(bumpResult, nil) - - ctx.finish(1) -} - // TestExclusiveGroup tests the sweeper exclusive group functionality. func TestExclusiveGroup(t *testing.T) { ctx := createSweeperTestContext(t) @@ -1919,71 +1847,6 @@ func TestExclusiveGroup(t *testing.T) { } } -// TestCpfp tests that the sweeper spends cpfp inputs at a fee rate that -// exceeds the parent tx fee rate. -func TestCpfp(t *testing.T) { - t.Skip("fix me") - - ctx := createSweeperTestContext(t) - - ctx.estimator.updateFees(1000, chainfee.FeePerKwFloor) - - // Offer an input with an unconfirmed parent tx to the sweeper. The - // parent tx pays 3000 sat/kw. - hash := chainhash.Hash{1} - input := input.MakeBaseInput( - &wire.OutPoint{Hash: hash}, - input.CommitmentTimeLock, - &input.SignDescriptor{ - Output: &wire.TxOut{ - Value: 330, - }, - KeyDesc: keychain.KeyDescriptor{ - PubKey: testPubKey, - }, - }, - 0, - &input.TxInfo{ - Weight: 300, - Fee: 900, - }, - ) - - feePref := FeeEstimateInfo{ConfTarget: 6} - result, err := ctx.sweeper.SweepInput( - &input, Params{Fee: feePref, Force: true}, - ) - require.NoError(t, err) - - // Increase the fee estimate to above the parent tx fee rate. - ctx.estimator.updateFees(5000, chainfee.FeePerKwFloor) - - // Signal a new block. This is a trigger for the sweeper to refresh fee - // estimates. - ctx.notifier.NotifyEpoch(1000) - - // Now we do expect a sweep transaction to be published with our input - // and an attached wallet utxo. - tx := ctx.receiveTx() - require.Len(t, tx.TxIn, 2) - require.Len(t, tx.TxOut, 1) - - // As inputs we have 10000 sats from the wallet and 330 sats from the - // cpfp input. The sweep tx is weight expected to be 759 units. There is - // an additional 300 weight units from the parent to include in the - // package, making a total of 1059. At 5000 sat/kw, the required fee for - // the package is 5295 sats. The parent already paid 900 sats, so there - // is 4395 sat remaining to be paid. The expected output value is - // therefore: 1_000_000 + 330 - 4395 = 995 935. - require.Equal(t, int64(995_935), tx.TxOut[0].Value) - - // Mine the tx and assert that the result is passed back. - ctx.backend.mine() - ctx.expectResult(result, nil) - - ctx.finish(1) -} - type testInput struct { *input.BaseInput @@ -2213,465 +2076,6 @@ func TestLockTimes(t *testing.T) { } } -// TestRequiredTxOuts checks that inputs having a required TxOut gets swept -// with sweep transactions paying into these outputs. -func TestRequiredTxOuts(t *testing.T) { - t.Skip("fix me") - - // Create some test inputs and locktime vars. - var inputs []*input.BaseInput - for i := 0; i < 20; i++ { - input := createTestInput( - int64(btcutil.SatoshiPerBitcoin+i*500), - input.CommitmentTimeLock, - ) - - inputs = append(inputs, &input) - } - - locktime1 := uint32(51) - locktime2 := uint32(52) - locktime3 := uint32(53) - - aPkScript := make([]byte, input.P2WPKHSize) - aPkScript[0] = 'a' - - bPkScript := make([]byte, input.P2WSHSize) - bPkScript[0] = 'b' - - cPkScript := make([]byte, input.P2PKHSize) - cPkScript[0] = 'c' - - dPkScript := make([]byte, input.P2SHSize) - dPkScript[0] = 'd' - - ePkScript := make([]byte, input.UnknownWitnessSize) - ePkScript[0] = 'e' - - fPkScript := make([]byte, input.P2WSHSize) - fPkScript[0] = 'f' - - testCases := []struct { - name string - inputs []*testInput - assertSweeps func(*testing.T, map[wire.OutPoint]*testInput, - []*wire.MsgTx) - }{ - { - // Single input with a required TX out that is smaller. - // We expect a change output to be added. - name: "single input, leftover change", - inputs: []*testInput{ - { - BaseInput: inputs[0], - reqTxOut: &wire.TxOut{ - PkScript: aPkScript, - Value: 100000, - }, - }, - }, - - // Since the required output value is small, we expect - // the rest after fees to go into a change output. - assertSweeps: func(t *testing.T, - _ map[wire.OutPoint]*testInput, - txs []*wire.MsgTx) { - - require.Equal(t, 1, len(txs)) - - tx := txs[0] - require.Equal(t, 1, len(tx.TxIn)) - - // We should have two outputs, the required - // output must be the first one. - require.Equal(t, 2, len(tx.TxOut)) - out := tx.TxOut[0] - require.Equal(t, aPkScript, out.PkScript) - require.Equal(t, int64(100000), out.Value) - }, - }, - { - // An input committing to a slightly smaller output, so - // it will pay its own fees. - name: "single input, no change", - inputs: []*testInput{ - { - BaseInput: inputs[0], - reqTxOut: &wire.TxOut{ - PkScript: aPkScript, - - // Fee will be about 5340 sats. - // Subtract a bit more to - // ensure no dust change output - // is manifested. - Value: inputs[0].SignDesc().Output.Value - 6300, - }, - }, - }, - - // We expect this single input/output pair. - assertSweeps: func(t *testing.T, - _ map[wire.OutPoint]*testInput, - txs []*wire.MsgTx) { - - require.Equal(t, 1, len(txs)) - - tx := txs[0] - require.Equal(t, 1, len(tx.TxIn)) - - require.Equal(t, 1, len(tx.TxOut)) - out := tx.TxOut[0] - require.Equal(t, aPkScript, out.PkScript) - require.Equal( - t, - inputs[0].SignDesc().Output.Value-6300, - out.Value, - ) - }, - }, - { - // Two inputs, where the first one required no tx out. - name: "two inputs, one with required tx out", - inputs: []*testInput{ - { - - // We add a normal, non-requiredTxOut - // input. We use test input 10, to make - // sure this has a higher yield than - // the other input, and will be - // attempted added first to the sweep - // tx. - BaseInput: inputs[10], - }, - { - // The second input requires a TxOut. - BaseInput: inputs[0], - reqTxOut: &wire.TxOut{ - PkScript: aPkScript, - Value: inputs[0].SignDesc().Output.Value, - }, - }, - }, - - // We expect the inputs to have been reordered. - assertSweeps: func(t *testing.T, - _ map[wire.OutPoint]*testInput, - txs []*wire.MsgTx) { - - require.Equal(t, 1, len(txs)) - - tx := txs[0] - require.Equal(t, 2, len(tx.TxIn)) - require.Equal(t, 2, len(tx.TxOut)) - - // The required TxOut should be the first one. - out := tx.TxOut[0] - require.Equal(t, aPkScript, out.PkScript) - require.Equal( - t, inputs[0].SignDesc().Output.Value, - out.Value, - ) - - // The first input should be the one having the - // required TxOut. - require.Len(t, tx.TxIn, 2) - require.Equal( - t, inputs[0].OutPoint(), - &tx.TxIn[0].PreviousOutPoint, - ) - - // Second one is the one without a required tx - // out. - require.Equal( - t, inputs[10].OutPoint(), - &tx.TxIn[1].PreviousOutPoint, - ) - }, - }, - - { - // An input committing to an output of equal value, just - // add input to pay fees. - name: "single input, extra fee input", - inputs: []*testInput{ - { - BaseInput: inputs[0], - reqTxOut: &wire.TxOut{ - PkScript: aPkScript, - Value: inputs[0].SignDesc().Output.Value, - }, - }, - }, - - // We expect an extra input and output. - assertSweeps: func(t *testing.T, - _ map[wire.OutPoint]*testInput, - txs []*wire.MsgTx) { - - require.Equal(t, 1, len(txs)) - - tx := txs[0] - require.Equal(t, 2, len(tx.TxIn)) - - require.Equal(t, 2, len(tx.TxOut)) - out := tx.TxOut[0] - require.Equal(t, aPkScript, out.PkScript) - require.Equal( - t, inputs[0].SignDesc().Output.Value, - out.Value, - ) - }, - }, - { - // Three inputs added, should be combined into a single - // sweep. - name: "three inputs", - inputs: []*testInput{ - { - BaseInput: inputs[0], - reqTxOut: &wire.TxOut{ - PkScript: aPkScript, - Value: inputs[0].SignDesc().Output.Value, - }, - }, - { - BaseInput: inputs[1], - reqTxOut: &wire.TxOut{ - PkScript: bPkScript, - Value: inputs[1].SignDesc().Output.Value, - }, - }, - { - BaseInput: inputs[2], - reqTxOut: &wire.TxOut{ - PkScript: cPkScript, - Value: inputs[2].SignDesc().Output.Value, - }, - }, - }, - - // We expect an extra input and output to pay fees. - assertSweeps: func(t *testing.T, - testInputs map[wire.OutPoint]*testInput, - txs []*wire.MsgTx) { - - require.Equal(t, 1, len(txs)) - - tx := txs[0] - require.Equal(t, 4, len(tx.TxIn)) - require.Equal(t, 4, len(tx.TxOut)) - - // The inputs and outputs must be in the same - // order. - for i, in := range tx.TxIn { - // Last one is the change input/output - // pair, so we'll skip it. - if i == 3 { - continue - } - - // Get this input to ensure the output - // on index i coresponsd to this one. - inp := testInputs[in.PreviousOutPoint] - require.NotNil(t, inp) - - require.Equal( - t, tx.TxOut[i].Value, - inp.SignDesc().Output.Value, - ) - } - }, - }, - { - // Six inputs added, which 3 different locktimes. - // Should result in 3 sweeps. - name: "six inputs", - inputs: []*testInput{ - { - BaseInput: inputs[0], - locktime: &locktime1, - reqTxOut: &wire.TxOut{ - PkScript: aPkScript, - Value: inputs[0].SignDesc().Output.Value, - }, - }, - { - BaseInput: inputs[1], - locktime: &locktime1, - reqTxOut: &wire.TxOut{ - PkScript: bPkScript, - Value: inputs[1].SignDesc().Output.Value, - }, - }, - { - BaseInput: inputs[2], - locktime: &locktime2, - reqTxOut: &wire.TxOut{ - PkScript: cPkScript, - Value: inputs[2].SignDesc().Output.Value, - }, - }, - { - BaseInput: inputs[3], - locktime: &locktime2, - reqTxOut: &wire.TxOut{ - PkScript: dPkScript, - Value: inputs[3].SignDesc().Output.Value, - }, - }, - { - BaseInput: inputs[4], - locktime: &locktime3, - reqTxOut: &wire.TxOut{ - PkScript: ePkScript, - Value: inputs[4].SignDesc().Output.Value, - }, - }, - { - BaseInput: inputs[5], - locktime: &locktime3, - reqTxOut: &wire.TxOut{ - PkScript: fPkScript, - Value: inputs[5].SignDesc().Output.Value, - }, - }, - }, - - // We expect three sweeps, each having two of our - // inputs, one extra input and output to pay fees. - assertSweeps: func(t *testing.T, - testInputs map[wire.OutPoint]*testInput, - txs []*wire.MsgTx) { - - require.Equal(t, 3, len(txs)) - - for _, tx := range txs { - require.Equal(t, 3, len(tx.TxIn)) - require.Equal(t, 3, len(tx.TxOut)) - - // The inputs and outputs must be in - // the same order. - for i, in := range tx.TxIn { - // Last one is the change - // output, so we'll skip it. - if i == 2 { - continue - } - - // Get this input to ensure the - // output on index i coresponsd - // to this one. - inp := testInputs[in.PreviousOutPoint] - require.NotNil(t, inp) - - require.Equal( - t, tx.TxOut[i].Value, - inp.SignDesc().Output.Value, - ) - - // Check that the locktimes are - // kept intact. - require.Equal( - t, tx.LockTime, - *inp.locktime, - ) - } - } - }, - }, - } - - for _, testCase := range testCases { - testCase := testCase - - t.Run(testCase.name, func(t *testing.T) { - ctx := createSweeperTestContext(t) - - // We increase the number of max inputs to a tx so that - // won't impact our test. - ctx.sweeper.cfg.MaxInputsPerTx = 100 - - // Sweep all test inputs. - var ( - inputs = make(map[wire.OutPoint]*testInput) - results = make(map[wire.OutPoint]chan Result) - ) - for _, inp := range testCase.inputs { - result, err := ctx.sweeper.SweepInput( - inp, Params{ - Fee: FeeEstimateInfo{ - ConfTarget: 6, - }, - }, - ) - if err != nil { - t.Fatal(err) - } - - op := inp.OutPoint() - results[*op] = result - inputs[*op] = inp - } - - // Send a new block epoch to trigger the sweeper to - // sweep the inputs. - ctx.notifier.NotifyEpoch(ctx.sweeper.currentHeight + 1) - - // Check the sweeps transactions, ensuring all inputs - // are there, and all the locktimes are satisfied. - var sweeps []*wire.MsgTx - Loop: - for { - select { - case tx := <-ctx.publishChan: - sweeps = append(sweeps, &tx) - case <-time.After(200 * time.Millisecond): - break Loop - } - } - - // Mine the sweeps. - ctx.backend.mine() - - // Results should all come back. - for _, resultChan := range results { - result := <-resultChan - if result.Err != nil { - t.Fatalf("expected input to be "+ - "swept: %v", result.Err) - } - } - - // Assert the transactions are what we expect. - testCase.assertSweeps(t, inputs, sweeps) - - // Finally we assert that all our test inputs were part - // of the sweeps, and that they were signed correctly. - sweptInputs := make(map[wire.OutPoint]struct{}) - for _, sweep := range sweeps { - swept := assertSignedIndex(t, sweep, inputs) - for op := range swept { - if _, ok := sweptInputs[op]; ok { - t.Fatalf("outpoint %v part of "+ - "previous sweep", op) - } - - sweptInputs[op] = struct{}{} - } - } - - require.Equal(t, len(inputs), len(sweptInputs)) - for op := range sweptInputs { - _, ok := inputs[op] - if !ok { - t.Fatalf("swept input %v not part of "+ - "test inputs", op) - } - } - }) - } -} - // TestSweeperShutdownHandling tests that we notify callers when the sweeper // cannot handle requests since it's in the process of shutting down. func TestSweeperShutdownHandling(t *testing.T) {