github.com/decred/dcrlnd@v0.7.6/channeldb/payment_control_test.go (about)

     1  package channeldb
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/rand"
     6  	"fmt"
     7  	"io"
     8  	"reflect"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/btcsuite/btcwallet/walletdb"
    13  	"github.com/davecgh/go-spew/spew"
    14  	"github.com/decred/dcrlnd/kvdb"
    15  	"github.com/decred/dcrlnd/lntypes"
    16  	"github.com/decred/dcrlnd/record"
    17  	"github.com/stretchr/testify/assert"
    18  	"github.com/stretchr/testify/require"
    19  )
    20  
    21  func genPreimage() (lntypes.Preimage, error) {
    22  	var preimage [32]byte
    23  	if _, err := io.ReadFull(rand.Reader, preimage[:]); err != nil {
    24  		return preimage, err
    25  	}
    26  	return preimage, nil
    27  }
    28  
    29  func genInfo() (*PaymentCreationInfo, *HTLCAttemptInfo,
    30  	lntypes.Preimage, error) {
    31  
    32  	preimage, err := genPreimage()
    33  	if err != nil {
    34  		return nil, nil, preimage, fmt.Errorf("unable to "+
    35  			"generate preimage: %v", err)
    36  	}
    37  
    38  	rhash := preimage.Hash()
    39  	attempt := NewHtlcAttemptInfo(
    40  		0, priv, *testRoute.Copy(), time.Time{}, nil,
    41  	)
    42  	return &PaymentCreationInfo{
    43  		PaymentIdentifier: rhash,
    44  		Value:             testRoute.ReceiverAmt(),
    45  		CreationTime:      time.Unix(time.Now().Unix(), 0),
    46  		PaymentRequest:    []byte("hola"),
    47  	}, attempt, preimage, nil
    48  }
    49  
    50  // TestPaymentControlSwitchFail checks that payment status returns to Failed
    51  // status after failing, and that InitPayment allows another HTLC for the
    52  // same payment hash.
    53  func TestPaymentControlSwitchFail(t *testing.T) {
    54  	t.Parallel()
    55  
    56  	db, cleanup, err := MakeTestDB()
    57  	defer cleanup()
    58  	if err != nil {
    59  		t.Fatalf("unable to init db: %v", err)
    60  	}
    61  
    62  	pControl := NewPaymentControl(db)
    63  
    64  	info, attempt, preimg, err := genInfo()
    65  	if err != nil {
    66  		t.Fatalf("unable to generate htlc message: %v", err)
    67  	}
    68  
    69  	// Sends base htlc message which initiate StatusInFlight.
    70  	err = pControl.InitPayment(info.PaymentIdentifier, info)
    71  	if err != nil {
    72  		t.Fatalf("unable to send htlc message: %v", err)
    73  	}
    74  
    75  	assertPaymentIndex(t, pControl, info.PaymentIdentifier)
    76  	assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight)
    77  	assertPaymentInfo(
    78  		t, pControl, info.PaymentIdentifier, info, nil, nil,
    79  	)
    80  
    81  	// Fail the payment, which should moved it to Failed.
    82  	failReason := FailureReasonNoRoute
    83  	_, err = pControl.Fail(info.PaymentIdentifier, failReason)
    84  	if err != nil {
    85  		t.Fatalf("unable to fail payment hash: %v", err)
    86  	}
    87  
    88  	// Verify the status is indeed Failed.
    89  	assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusFailed)
    90  	assertPaymentInfo(
    91  		t, pControl, info.PaymentIdentifier, info, &failReason, nil,
    92  	)
    93  
    94  	// Lookup the payment so we can get its old sequence number before it is
    95  	// overwritten.
    96  	payment, err := pControl.FetchPayment(info.PaymentIdentifier)
    97  	assert.NoError(t, err)
    98  
    99  	// Sends the htlc again, which should succeed since the prior payment
   100  	// failed.
   101  	err = pControl.InitPayment(info.PaymentIdentifier, info)
   102  	if err != nil {
   103  		t.Fatalf("unable to send htlc message: %v", err)
   104  	}
   105  
   106  	// Check that our index has been updated, and the old index has been
   107  	// removed.
   108  	assertPaymentIndex(t, pControl, info.PaymentIdentifier)
   109  	assertNoIndex(t, pControl, payment.SequenceNum)
   110  
   111  	assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight)
   112  	assertPaymentInfo(
   113  		t, pControl, info.PaymentIdentifier, info, nil, nil,
   114  	)
   115  
   116  	// Record a new attempt. In this test scenario, the attempt fails.
   117  	// However, this is not communicated to control tower in the current
   118  	// implementation. It only registers the initiation of the attempt.
   119  	_, err = pControl.RegisterAttempt(info.PaymentIdentifier, attempt)
   120  	if err != nil {
   121  		t.Fatalf("unable to register attempt: %v", err)
   122  	}
   123  
   124  	htlcReason := HTLCFailUnreadable
   125  	_, err = pControl.FailAttempt(
   126  		info.PaymentIdentifier, attempt.AttemptID,
   127  		&HTLCFailInfo{
   128  			Reason: htlcReason,
   129  		},
   130  	)
   131  	if err != nil {
   132  		t.Fatal(err)
   133  	}
   134  	assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight)
   135  
   136  	htlc := &htlcStatus{
   137  		HTLCAttemptInfo: attempt,
   138  		failure:         &htlcReason,
   139  	}
   140  
   141  	assertPaymentInfo(t, pControl, info.PaymentIdentifier, info, nil, htlc)
   142  
   143  	// Record another attempt.
   144  	attempt.AttemptID = 1
   145  	_, err = pControl.RegisterAttempt(info.PaymentIdentifier, attempt)
   146  	if err != nil {
   147  		t.Fatalf("unable to send htlc message: %v", err)
   148  	}
   149  	assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight)
   150  
   151  	htlc = &htlcStatus{
   152  		HTLCAttemptInfo: attempt,
   153  	}
   154  
   155  	assertPaymentInfo(
   156  		t, pControl, info.PaymentIdentifier, info, nil, htlc,
   157  	)
   158  
   159  	// Settle the attempt and verify that status was changed to
   160  	// StatusSucceeded.
   161  	payment, err = pControl.SettleAttempt(
   162  		info.PaymentIdentifier, attempt.AttemptID,
   163  		&HTLCSettleInfo{
   164  			Preimage: preimg,
   165  		},
   166  	)
   167  	if err != nil {
   168  		t.Fatalf("error shouldn't have been received, got: %v", err)
   169  	}
   170  
   171  	if len(payment.HTLCs) != 2 {
   172  		t.Fatalf("payment should have two htlcs, got: %d",
   173  			len(payment.HTLCs))
   174  	}
   175  
   176  	err = assertRouteEqual(&payment.HTLCs[0].Route, &attempt.Route)
   177  	if err != nil {
   178  		t.Fatalf("unexpected route returned: %v vs %v: %v",
   179  			spew.Sdump(attempt.Route),
   180  			spew.Sdump(payment.HTLCs[0].Route), err)
   181  	}
   182  
   183  	assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusSucceeded)
   184  
   185  	htlc.settle = &preimg
   186  	assertPaymentInfo(
   187  		t, pControl, info.PaymentIdentifier, info, nil, htlc,
   188  	)
   189  
   190  	// Attempt a final payment, which should now fail since the prior
   191  	// payment succeed.
   192  	err = pControl.InitPayment(info.PaymentIdentifier, info)
   193  	if err != ErrAlreadyPaid {
   194  		t.Fatalf("unable to send htlc message: %v", err)
   195  	}
   196  }
   197  
   198  // TestPaymentControlSwitchDoubleSend checks the ability of payment control to
   199  // prevent double sending of htlc message, when message is in StatusInFlight.
   200  func TestPaymentControlSwitchDoubleSend(t *testing.T) {
   201  	t.Parallel()
   202  
   203  	db, cleanup, err := MakeTestDB()
   204  	defer cleanup()
   205  
   206  	if err != nil {
   207  		t.Fatalf("unable to init db: %v", err)
   208  	}
   209  
   210  	pControl := NewPaymentControl(db)
   211  
   212  	info, attempt, preimg, err := genInfo()
   213  	if err != nil {
   214  		t.Fatalf("unable to generate htlc message: %v", err)
   215  	}
   216  
   217  	// Sends base htlc message which initiate base status and move it to
   218  	// StatusInFlight and verifies that it was changed.
   219  	err = pControl.InitPayment(info.PaymentIdentifier, info)
   220  	if err != nil {
   221  		t.Fatalf("unable to send htlc message: %v", err)
   222  	}
   223  
   224  	assertPaymentIndex(t, pControl, info.PaymentIdentifier)
   225  	assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight)
   226  	assertPaymentInfo(
   227  		t, pControl, info.PaymentIdentifier, info, nil, nil,
   228  	)
   229  
   230  	// Try to initiate double sending of htlc message with the same
   231  	// payment hash, should result in error indicating that payment has
   232  	// already been sent.
   233  	err = pControl.InitPayment(info.PaymentIdentifier, info)
   234  	if err != ErrPaymentInFlight {
   235  		t.Fatalf("payment control wrong behaviour: " +
   236  			"double sending must trigger ErrPaymentInFlight error")
   237  	}
   238  
   239  	// Record an attempt.
   240  	_, err = pControl.RegisterAttempt(info.PaymentIdentifier, attempt)
   241  	if err != nil {
   242  		t.Fatalf("unable to send htlc message: %v", err)
   243  	}
   244  	assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight)
   245  
   246  	htlc := &htlcStatus{
   247  		HTLCAttemptInfo: attempt,
   248  	}
   249  	assertPaymentInfo(
   250  		t, pControl, info.PaymentIdentifier, info, nil, htlc,
   251  	)
   252  
   253  	// Sends base htlc message which initiate StatusInFlight.
   254  	err = pControl.InitPayment(info.PaymentIdentifier, info)
   255  	if err != ErrPaymentInFlight {
   256  		t.Fatalf("payment control wrong behaviour: " +
   257  			"double sending must trigger ErrPaymentInFlight error")
   258  	}
   259  
   260  	// After settling, the error should be ErrAlreadyPaid.
   261  	_, err = pControl.SettleAttempt(
   262  		info.PaymentIdentifier, attempt.AttemptID,
   263  		&HTLCSettleInfo{
   264  			Preimage: preimg,
   265  		},
   266  	)
   267  	if err != nil {
   268  		t.Fatalf("error shouldn't have been received, got: %v", err)
   269  	}
   270  	assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusSucceeded)
   271  
   272  	htlc.settle = &preimg
   273  	assertPaymentInfo(t, pControl, info.PaymentIdentifier, info, nil, htlc)
   274  
   275  	err = pControl.InitPayment(info.PaymentIdentifier, info)
   276  	if err != ErrAlreadyPaid {
   277  		t.Fatalf("unable to send htlc message: %v", err)
   278  	}
   279  }
   280  
   281  // TestPaymentControlSuccessesWithoutInFlight checks that the payment
   282  // control will disallow calls to Success when no payment is in flight.
   283  func TestPaymentControlSuccessesWithoutInFlight(t *testing.T) {
   284  	t.Parallel()
   285  
   286  	db, cleanup, err := MakeTestDB()
   287  	defer cleanup()
   288  
   289  	if err != nil {
   290  		t.Fatalf("unable to init db: %v", err)
   291  	}
   292  
   293  	pControl := NewPaymentControl(db)
   294  
   295  	info, _, preimg, err := genInfo()
   296  	if err != nil {
   297  		t.Fatalf("unable to generate htlc message: %v", err)
   298  	}
   299  
   300  	// Attempt to complete the payment should fail.
   301  	_, err = pControl.SettleAttempt(
   302  		info.PaymentIdentifier, 0,
   303  		&HTLCSettleInfo{
   304  			Preimage: preimg,
   305  		},
   306  	)
   307  	if err != ErrPaymentNotInitiated {
   308  		t.Fatalf("expected ErrPaymentNotInitiated, got %v", err)
   309  	}
   310  
   311  	assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusUnknown)
   312  }
   313  
   314  // TestPaymentControlFailsWithoutInFlight checks that a strict payment
   315  // control will disallow calls to Fail when no payment is in flight.
   316  func TestPaymentControlFailsWithoutInFlight(t *testing.T) {
   317  	t.Parallel()
   318  
   319  	db, cleanup, err := MakeTestDB()
   320  	defer cleanup()
   321  
   322  	if err != nil {
   323  		t.Fatalf("unable to init db: %v", err)
   324  	}
   325  
   326  	pControl := NewPaymentControl(db)
   327  
   328  	info, _, _, err := genInfo()
   329  	if err != nil {
   330  		t.Fatalf("unable to generate htlc message: %v", err)
   331  	}
   332  
   333  	// Calling Fail should return an error.
   334  	_, err = pControl.Fail(info.PaymentIdentifier, FailureReasonNoRoute)
   335  	if err != ErrPaymentNotInitiated {
   336  		t.Fatalf("expected ErrPaymentNotInitiated, got %v", err)
   337  	}
   338  
   339  	assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusUnknown)
   340  }
   341  
   342  // TestPaymentControlDeleteNonInFlight checks that calling DeletePayments only
   343  // deletes payments from the database that are not in-flight.
   344  func TestPaymentControlDeleteNonInFligt(t *testing.T) {
   345  	t.Parallel()
   346  
   347  	db, cleanup, err := MakeTestDB()
   348  	defer cleanup()
   349  
   350  	if err != nil {
   351  		t.Fatalf("unable to init db: %v", err)
   352  	}
   353  
   354  	// Create a sequence number for duplicate payments that will not collide
   355  	// with the sequence numbers for the payments we create. These values
   356  	// start at 1, so 9999 is a safe bet for this test.
   357  	var duplicateSeqNr = 9999
   358  
   359  	pControl := NewPaymentControl(db)
   360  
   361  	payments := []struct {
   362  		failed       bool
   363  		success      bool
   364  		hasDuplicate bool
   365  	}{
   366  		{
   367  			failed:       true,
   368  			success:      false,
   369  			hasDuplicate: false,
   370  		},
   371  		{
   372  			failed:       false,
   373  			success:      true,
   374  			hasDuplicate: false,
   375  		},
   376  		{
   377  			failed:       false,
   378  			success:      false,
   379  			hasDuplicate: false,
   380  		},
   381  		{
   382  			failed:       false,
   383  			success:      true,
   384  			hasDuplicate: true,
   385  		},
   386  	}
   387  
   388  	var numSuccess, numInflight int
   389  
   390  	for _, p := range payments {
   391  		info, attempt, preimg, err := genInfo()
   392  		if err != nil {
   393  			t.Fatalf("unable to generate htlc message: %v", err)
   394  		}
   395  
   396  		// Sends base htlc message which initiate StatusInFlight.
   397  		err = pControl.InitPayment(info.PaymentIdentifier, info)
   398  		if err != nil {
   399  			t.Fatalf("unable to send htlc message: %v", err)
   400  		}
   401  		_, err = pControl.RegisterAttempt(info.PaymentIdentifier, attempt)
   402  		if err != nil {
   403  			t.Fatalf("unable to send htlc message: %v", err)
   404  		}
   405  
   406  		htlc := &htlcStatus{
   407  			HTLCAttemptInfo: attempt,
   408  		}
   409  
   410  		if p.failed {
   411  			// Fail the payment attempt.
   412  			htlcFailure := HTLCFailUnreadable
   413  			_, err := pControl.FailAttempt(
   414  				info.PaymentIdentifier, attempt.AttemptID,
   415  				&HTLCFailInfo{
   416  					Reason: htlcFailure,
   417  				},
   418  			)
   419  			if err != nil {
   420  				t.Fatalf("unable to fail htlc: %v", err)
   421  			}
   422  
   423  			// Fail the payment, which should moved it to Failed.
   424  			failReason := FailureReasonNoRoute
   425  			_, err = pControl.Fail(info.PaymentIdentifier, failReason)
   426  			if err != nil {
   427  				t.Fatalf("unable to fail payment hash: %v", err)
   428  			}
   429  
   430  			// Verify the status is indeed Failed.
   431  			assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusFailed)
   432  
   433  			htlc.failure = &htlcFailure
   434  			assertPaymentInfo(
   435  				t, pControl, info.PaymentIdentifier, info,
   436  				&failReason, htlc,
   437  			)
   438  		} else if p.success {
   439  			// Verifies that status was changed to StatusSucceeded.
   440  			_, err := pControl.SettleAttempt(
   441  				info.PaymentIdentifier, attempt.AttemptID,
   442  				&HTLCSettleInfo{
   443  					Preimage: preimg,
   444  				},
   445  			)
   446  			if err != nil {
   447  				t.Fatalf("error shouldn't have been received, got: %v", err)
   448  			}
   449  
   450  			assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusSucceeded)
   451  
   452  			htlc.settle = &preimg
   453  			assertPaymentInfo(
   454  				t, pControl, info.PaymentIdentifier, info, nil, htlc,
   455  			)
   456  
   457  			numSuccess++
   458  		} else {
   459  			assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight)
   460  			assertPaymentInfo(
   461  				t, pControl, info.PaymentIdentifier, info, nil, htlc,
   462  			)
   463  
   464  			numInflight++
   465  		}
   466  
   467  		// If the payment is intended to have a duplicate payment, we
   468  		// add one.
   469  		if p.hasDuplicate {
   470  			appendDuplicatePayment(
   471  				t, pControl.db, info.PaymentIdentifier,
   472  				uint64(duplicateSeqNr), preimg,
   473  			)
   474  			duplicateSeqNr++
   475  			numSuccess++
   476  		}
   477  	}
   478  
   479  	// Delete all failed payments.
   480  	if err := db.DeletePayments(true, false); err != nil {
   481  		t.Fatal(err)
   482  	}
   483  
   484  	// This should leave the succeeded and in-flight payments.
   485  	dbPayments, err := db.FetchPayments()
   486  	if err != nil {
   487  		t.Fatal(err)
   488  	}
   489  
   490  	if len(dbPayments) != numSuccess+numInflight {
   491  		t.Fatalf("expected %d payments, got %d",
   492  			numSuccess+numInflight, len(dbPayments))
   493  	}
   494  
   495  	var s, i int
   496  	for _, p := range dbPayments {
   497  		fmt.Println("fetch payment has status", p.Status)
   498  		switch p.Status {
   499  		case StatusSucceeded:
   500  			s++
   501  		case StatusInFlight:
   502  			i++
   503  		}
   504  	}
   505  
   506  	if s != numSuccess {
   507  		t.Fatalf("expected %d succeeded payments , got %d",
   508  			numSuccess, s)
   509  	}
   510  	if i != numInflight {
   511  		t.Fatalf("expected %d in-flight payments, got %d",
   512  			numInflight, i)
   513  	}
   514  
   515  	// Now delete all payments except in-flight.
   516  	if err := db.DeletePayments(false, false); err != nil {
   517  		t.Fatal(err)
   518  	}
   519  
   520  	// This should leave the in-flight payment.
   521  	dbPayments, err = db.FetchPayments()
   522  	if err != nil {
   523  		t.Fatal(err)
   524  	}
   525  
   526  	if len(dbPayments) != numInflight {
   527  		t.Fatalf("expected %d payments, got %d", numInflight,
   528  			len(dbPayments))
   529  	}
   530  
   531  	for _, p := range dbPayments {
   532  		if p.Status != StatusInFlight {
   533  			t.Fatalf("expected in-fligth status, got %v", p.Status)
   534  		}
   535  	}
   536  
   537  	// Finally, check that we only have a single index left in the payment
   538  	// index bucket.
   539  	var indexCount int
   540  	err = kvdb.View(db, func(tx walletdb.ReadTx) error {
   541  		index := tx.ReadBucket(paymentsIndexBucket)
   542  
   543  		return index.ForEach(func(k, v []byte) error {
   544  			indexCount++
   545  			return nil
   546  		})
   547  	}, func() { indexCount = 0 })
   548  	require.NoError(t, err)
   549  
   550  	require.Equal(t, 1, indexCount)
   551  }
   552  
   553  // TestPaymentControlDeletePayments tests that DeletePayments correcly deletes
   554  // information about completed payments from the database.
   555  func TestPaymentControlDeletePayments(t *testing.T) {
   556  	t.Parallel()
   557  
   558  	db, cleanup, err := MakeTestDB()
   559  	defer cleanup()
   560  	require.NoError(t, err, "unable to init db")
   561  
   562  	pControl := NewPaymentControl(db)
   563  
   564  	// Register three payments:
   565  	// 1. A payment with two failed attempts.
   566  	// 2. A Payment with one failed and one settled attempt.
   567  	// 3. A payment with one failed and one in-flight attempt.
   568  	payments := []*payment{
   569  		{status: StatusFailed},
   570  		{status: StatusSucceeded},
   571  		{status: StatusInFlight},
   572  	}
   573  
   574  	// Use helper function to register the test payments in the data and
   575  	// populate the data to the payments slice.
   576  	createTestPayments(t, pControl, payments)
   577  
   578  	// Check that all payments are there as we added them.
   579  	assertPayments(t, db, payments)
   580  
   581  	// Delete HTLC attempts for failed payments only.
   582  	require.NoError(t, db.DeletePayments(true, true))
   583  
   584  	// The failed payment is the only altered one.
   585  	payments[0].htlcs = 0
   586  	assertPayments(t, db, payments)
   587  
   588  	// Delete failed attempts for all payments.
   589  	require.NoError(t, db.DeletePayments(false, true))
   590  
   591  	// The failed attempts should be deleted, except for the in-flight
   592  	// payment, that shouldn't be altered until it has completed.
   593  	payments[1].htlcs = 1
   594  	assertPayments(t, db, payments)
   595  
   596  	// Now delete all failed payments.
   597  	require.NoError(t, db.DeletePayments(true, false))
   598  
   599  	assertPayments(t, db, payments[1:])
   600  
   601  	// Finally delete all completed payments.
   602  	require.NoError(t, db.DeletePayments(false, false))
   603  
   604  	assertPayments(t, db, payments[2:])
   605  }
   606  
   607  // TestPaymentControlDeleteSinglePayment tests that DeletePayment correcly
   608  // deletes information about a completed payment from the database.
   609  func TestPaymentControlDeleteSinglePayment(t *testing.T) {
   610  	t.Parallel()
   611  
   612  	db, cleanup, err := MakeTestDB()
   613  	defer cleanup()
   614  	require.NoError(t, err, "unable to init db")
   615  
   616  	pControl := NewPaymentControl(db)
   617  
   618  	// Register four payments:
   619  	// All payments will have one failed HTLC attempt and one HTLC attempt
   620  	// according to its final status.
   621  	// 1. A payment with two failed attempts.
   622  	// 2. Another payment with two failed attempts.
   623  	// 3. A Payment with one failed and one settled attempt.
   624  	// 4. A payment with one failed and one in-flight attempt.
   625  
   626  	// Initiate payments, which is a slice of payment that is used as
   627  	// template to create the corresponding test payments in the database.
   628  	//
   629  	// Note: The payment id and number of htlc attempts of each payment will
   630  	// be added to this slice when creating the payments below.
   631  	// This allows the slice to be used directly for testing purposes.
   632  	payments := []*payment{
   633  		{status: StatusFailed},
   634  		{status: StatusFailed},
   635  		{status: StatusSucceeded},
   636  		{status: StatusInFlight},
   637  	}
   638  
   639  	// Use helper function to register the test payments in the data and
   640  	// populate the data to the payments slice.
   641  	createTestPayments(t, pControl, payments)
   642  
   643  	// Check that all payments are there as we added them.
   644  	assertPayments(t, db, payments)
   645  
   646  	// Delete HTLC attempts for first payment only.
   647  	require.NoError(t, db.DeletePayment(payments[0].id, true))
   648  
   649  	// The first payment is the only altered one as its failed HTLC should
   650  	// have been removed but is still present as payment.
   651  	payments[0].htlcs = 0
   652  	assertPayments(t, db, payments)
   653  
   654  	// Delete the first payment completely.
   655  	require.NoError(t, db.DeletePayment(payments[0].id, false))
   656  
   657  	// The first payment should have been deleted.
   658  	assertPayments(t, db, payments[1:])
   659  
   660  	// Now delete the second payment completely.
   661  	require.NoError(t, db.DeletePayment(payments[1].id, false))
   662  
   663  	// The Second payment should have been deleted.
   664  	assertPayments(t, db, payments[2:])
   665  
   666  	// Delete failed HTLC attempts for the third payment.
   667  	require.NoError(t, db.DeletePayment(payments[2].id, true))
   668  
   669  	// Only the successful HTLC attempt should be left for the third payment.
   670  	payments[2].htlcs = 1
   671  	assertPayments(t, db, payments[2:])
   672  
   673  	// Now delete the third payment completely.
   674  	require.NoError(t, db.DeletePayment(payments[2].id, false))
   675  
   676  	// Only the last payment should be left.
   677  	assertPayments(t, db, payments[3:])
   678  
   679  	// Deleting HTLC attempts from InFlight payments should not work and an
   680  	// error returned.
   681  	require.Error(t, db.DeletePayment(payments[3].id, true))
   682  
   683  	// The payment is InFlight and therefore should not have been altered.
   684  	assertPayments(t, db, payments[3:])
   685  
   686  	// Finally deleting the InFlight payment should also not work and an
   687  	// error returned.
   688  	require.Error(t, db.DeletePayment(payments[3].id, false))
   689  
   690  	// The payment is InFlight and therefore should not have been altered.
   691  	assertPayments(t, db, payments[3:])
   692  }
   693  
   694  // TestPaymentControlMultiShard checks the ability of payment control to
   695  // have multiple in-flight HTLCs for a single payment.
   696  func TestPaymentControlMultiShard(t *testing.T) {
   697  	t.Parallel()
   698  
   699  	// We will register three HTLC attempts, and always fail the second
   700  	// one. We'll generate all combinations of settling/failing the first
   701  	// and third HTLC, and assert that the payment status end up as we
   702  	// expect.
   703  	type testCase struct {
   704  		settleFirst bool
   705  		settleLast  bool
   706  	}
   707  
   708  	var tests []testCase
   709  	for _, f := range []bool{true, false} {
   710  		for _, l := range []bool{true, false} {
   711  			tests = append(tests, testCase{f, l})
   712  		}
   713  	}
   714  
   715  	runSubTest := func(t *testing.T, test testCase) {
   716  		db, cleanup, err := MakeTestDB()
   717  		defer cleanup()
   718  
   719  		if err != nil {
   720  			t.Fatalf("unable to init db: %v", err)
   721  		}
   722  
   723  		pControl := NewPaymentControl(db)
   724  
   725  		info, attempt, preimg, err := genInfo()
   726  		if err != nil {
   727  			t.Fatalf("unable to generate htlc message: %v", err)
   728  		}
   729  
   730  		// Init the payment, moving it to the StatusInFlight state.
   731  		err = pControl.InitPayment(info.PaymentIdentifier, info)
   732  		if err != nil {
   733  			t.Fatalf("unable to send htlc message: %v", err)
   734  		}
   735  
   736  		assertPaymentIndex(t, pControl, info.PaymentIdentifier)
   737  		assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight)
   738  		assertPaymentInfo(
   739  			t, pControl, info.PaymentIdentifier, info, nil, nil,
   740  		)
   741  
   742  		// Create three unique attempts we'll use for the test, and
   743  		// register them with the payment control. We set each
   744  		// attempts's value to one third of the payment amount, and
   745  		// populate the MPP options.
   746  		shardAmt := info.Value / 3
   747  		attempt.Route.FinalHop().AmtToForward = shardAmt
   748  		attempt.Route.FinalHop().MPP = record.NewMPP(
   749  			info.Value, [32]byte{1},
   750  		)
   751  
   752  		var attempts []*HTLCAttemptInfo
   753  		for i := uint64(0); i < 3; i++ {
   754  			a := *attempt
   755  			a.AttemptID = i
   756  			attempts = append(attempts, &a)
   757  
   758  			_, err = pControl.RegisterAttempt(info.PaymentIdentifier, &a)
   759  			if err != nil {
   760  				t.Fatalf("unable to send htlc message: %v", err)
   761  			}
   762  			assertPaymentStatus(
   763  				t, pControl, info.PaymentIdentifier, StatusInFlight,
   764  			)
   765  
   766  			htlc := &htlcStatus{
   767  				HTLCAttemptInfo: &a,
   768  			}
   769  			assertPaymentInfo(
   770  				t, pControl, info.PaymentIdentifier, info, nil, htlc,
   771  			)
   772  		}
   773  
   774  		// For a fourth attempt, check that attempting to
   775  		// register it will fail since the total sent amount
   776  		// will be too large.
   777  		b := *attempt
   778  		b.AttemptID = 3
   779  		_, err = pControl.RegisterAttempt(info.PaymentIdentifier, &b)
   780  		if err != ErrValueExceedsAmt {
   781  			t.Fatalf("expected ErrValueExceedsAmt, got: %v",
   782  				err)
   783  		}
   784  
   785  		// Fail the second attempt.
   786  		a := attempts[1]
   787  		htlcFail := HTLCFailUnreadable
   788  		_, err = pControl.FailAttempt(
   789  			info.PaymentIdentifier, a.AttemptID,
   790  			&HTLCFailInfo{
   791  				Reason: htlcFail,
   792  			},
   793  		)
   794  		if err != nil {
   795  			t.Fatal(err)
   796  		}
   797  
   798  		htlc := &htlcStatus{
   799  			HTLCAttemptInfo: a,
   800  			failure:         &htlcFail,
   801  		}
   802  		assertPaymentInfo(
   803  			t, pControl, info.PaymentIdentifier, info, nil, htlc,
   804  		)
   805  
   806  		// Payment should still be in-flight.
   807  		assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight)
   808  
   809  		// Depending on the test case, settle or fail the first attempt.
   810  		a = attempts[0]
   811  		htlc = &htlcStatus{
   812  			HTLCAttemptInfo: a,
   813  		}
   814  
   815  		var firstFailReason *FailureReason
   816  		if test.settleFirst {
   817  			_, err := pControl.SettleAttempt(
   818  				info.PaymentIdentifier, a.AttemptID,
   819  				&HTLCSettleInfo{
   820  					Preimage: preimg,
   821  				},
   822  			)
   823  			if err != nil {
   824  				t.Fatalf("error shouldn't have been "+
   825  					"received, got: %v", err)
   826  			}
   827  
   828  			// Assert that the HTLC has had the preimage recorded.
   829  			htlc.settle = &preimg
   830  			assertPaymentInfo(
   831  				t, pControl, info.PaymentIdentifier, info, nil, htlc,
   832  			)
   833  		} else {
   834  			_, err := pControl.FailAttempt(
   835  				info.PaymentIdentifier, a.AttemptID,
   836  				&HTLCFailInfo{
   837  					Reason: htlcFail,
   838  				},
   839  			)
   840  			if err != nil {
   841  				t.Fatalf("error shouldn't have been "+
   842  					"received, got: %v", err)
   843  			}
   844  
   845  			// Assert the failure was recorded.
   846  			htlc.failure = &htlcFail
   847  			assertPaymentInfo(
   848  				t, pControl, info.PaymentIdentifier, info, nil, htlc,
   849  			)
   850  
   851  			// We also record a payment level fail, to move it into
   852  			// a terminal state.
   853  			failReason := FailureReasonNoRoute
   854  			_, err = pControl.Fail(info.PaymentIdentifier, failReason)
   855  			if err != nil {
   856  				t.Fatalf("unable to fail payment hash: %v", err)
   857  			}
   858  
   859  			// Record the reason we failed the payment, such that
   860  			// we can assert this later in the test.
   861  			firstFailReason = &failReason
   862  		}
   863  
   864  		// The payment should still be considered in-flight, since there
   865  		// is still an active HTLC.
   866  		assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight)
   867  
   868  		// Try to register yet another attempt. This should fail now
   869  		// that the payment has reached a terminal condition.
   870  		b = *attempt
   871  		b.AttemptID = 3
   872  		_, err = pControl.RegisterAttempt(info.PaymentIdentifier, &b)
   873  		if err != ErrPaymentTerminal {
   874  			t.Fatalf("expected ErrPaymentTerminal, got: %v", err)
   875  		}
   876  
   877  		assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight)
   878  
   879  		// Settle or fail the remaining attempt based on the testcase.
   880  		a = attempts[2]
   881  		htlc = &htlcStatus{
   882  			HTLCAttemptInfo: a,
   883  		}
   884  		if test.settleLast {
   885  			// Settle the last outstanding attempt.
   886  			_, err = pControl.SettleAttempt(
   887  				info.PaymentIdentifier, a.AttemptID,
   888  				&HTLCSettleInfo{
   889  					Preimage: preimg,
   890  				},
   891  			)
   892  			if err != nil {
   893  				t.Fatalf("error shouldn't have been "+
   894  					"received, got: %v", err)
   895  			}
   896  
   897  			htlc.settle = &preimg
   898  			assertPaymentInfo(
   899  				t, pControl, info.PaymentIdentifier, info,
   900  				firstFailReason, htlc,
   901  			)
   902  		} else {
   903  			// Fail the attempt.
   904  			_, err := pControl.FailAttempt(
   905  				info.PaymentIdentifier, a.AttemptID,
   906  				&HTLCFailInfo{
   907  					Reason: htlcFail,
   908  				},
   909  			)
   910  			if err != nil {
   911  				t.Fatalf("error shouldn't have been "+
   912  					"received, got: %v", err)
   913  			}
   914  
   915  			// Assert the failure was recorded.
   916  			htlc.failure = &htlcFail
   917  			assertPaymentInfo(
   918  				t, pControl, info.PaymentIdentifier, info,
   919  				firstFailReason, htlc,
   920  			)
   921  
   922  			// Check that we can override any perevious terminal
   923  			// failure. This is to allow multiple concurrent shard
   924  			// write a terminal failure to the database without
   925  			// syncing.
   926  			failReason := FailureReasonPaymentDetails
   927  			_, err = pControl.Fail(info.PaymentIdentifier, failReason)
   928  			if err != nil {
   929  				t.Fatalf("unable to fail payment hash: %v", err)
   930  			}
   931  		}
   932  
   933  		// If any of the two attempts settled, the payment should end
   934  		// up in the Succeeded state. If both failed the payment should
   935  		// also be Failed at this poinnt.
   936  		finalStatus := StatusFailed
   937  		if test.settleFirst || test.settleLast {
   938  			finalStatus = StatusSucceeded
   939  		}
   940  
   941  		assertPaymentStatus(t, pControl, info.PaymentIdentifier, finalStatus)
   942  
   943  		// Finally assert we cannot register more attempts.
   944  		_, err = pControl.RegisterAttempt(info.PaymentIdentifier, &b)
   945  		require.Equal(t, ErrPaymentTerminal, err)
   946  	}
   947  
   948  	for _, test := range tests {
   949  		test := test
   950  		subTest := fmt.Sprintf("first=%v, second=%v",
   951  			test.settleFirst, test.settleLast)
   952  
   953  		t.Run(subTest, func(t *testing.T) {
   954  			runSubTest(t, test)
   955  		})
   956  	}
   957  }
   958  
   959  func TestPaymentControlMPPRecordValidation(t *testing.T) {
   960  	t.Parallel()
   961  
   962  	db, cleanup, err := MakeTestDB()
   963  	defer cleanup()
   964  
   965  	if err != nil {
   966  		t.Fatalf("unable to init db: %v", err)
   967  	}
   968  
   969  	pControl := NewPaymentControl(db)
   970  
   971  	info, attempt, _, err := genInfo()
   972  	if err != nil {
   973  		t.Fatalf("unable to generate htlc message: %v", err)
   974  	}
   975  
   976  	// Init the payment.
   977  	err = pControl.InitPayment(info.PaymentIdentifier, info)
   978  	if err != nil {
   979  		t.Fatalf("unable to send htlc message: %v", err)
   980  	}
   981  
   982  	// Create three unique attempts we'll use for the test, and
   983  	// register them with the payment control. We set each
   984  	// attempts's value to one third of the payment amount, and
   985  	// populate the MPP options.
   986  	shardAmt := info.Value / 3
   987  	attempt.Route.FinalHop().AmtToForward = shardAmt
   988  	attempt.Route.FinalHop().MPP = record.NewMPP(
   989  		info.Value, [32]byte{1},
   990  	)
   991  
   992  	_, err = pControl.RegisterAttempt(info.PaymentIdentifier, attempt)
   993  	if err != nil {
   994  		t.Fatalf("unable to send htlc message: %v", err)
   995  	}
   996  
   997  	// Now try to register a non-MPP attempt, which should fail.
   998  	b := *attempt
   999  	b.AttemptID = 1
  1000  	b.Route.FinalHop().MPP = nil
  1001  	_, err = pControl.RegisterAttempt(info.PaymentIdentifier, &b)
  1002  	if err != ErrMPPayment {
  1003  		t.Fatalf("expected ErrMPPayment, got: %v", err)
  1004  	}
  1005  
  1006  	// Try to register attempt one with a different payment address.
  1007  	b.Route.FinalHop().MPP = record.NewMPP(
  1008  		info.Value, [32]byte{2},
  1009  	)
  1010  	_, err = pControl.RegisterAttempt(info.PaymentIdentifier, &b)
  1011  	if err != ErrMPPPaymentAddrMismatch {
  1012  		t.Fatalf("expected ErrMPPPaymentAddrMismatch, got: %v", err)
  1013  	}
  1014  
  1015  	// Try registering one with a different total amount.
  1016  	b.Route.FinalHop().MPP = record.NewMPP(
  1017  		info.Value/2, [32]byte{1},
  1018  	)
  1019  	_, err = pControl.RegisterAttempt(info.PaymentIdentifier, &b)
  1020  	if err != ErrMPPTotalAmountMismatch {
  1021  		t.Fatalf("expected ErrMPPTotalAmountMismatch, got: %v", err)
  1022  	}
  1023  
  1024  	// Create and init a new payment. This time we'll check that we cannot
  1025  	// register an MPP attempt if we already registered a non-MPP one.
  1026  	info, attempt, _, err = genInfo()
  1027  	if err != nil {
  1028  		t.Fatalf("unable to generate htlc message: %v", err)
  1029  	}
  1030  
  1031  	err = pControl.InitPayment(info.PaymentIdentifier, info)
  1032  	if err != nil {
  1033  		t.Fatalf("unable to send htlc message: %v", err)
  1034  	}
  1035  
  1036  	attempt.Route.FinalHop().MPP = nil
  1037  	_, err = pControl.RegisterAttempt(info.PaymentIdentifier, attempt)
  1038  	if err != nil {
  1039  		t.Fatalf("unable to send htlc message: %v", err)
  1040  	}
  1041  
  1042  	// Attempt to register an MPP attempt, which should fail.
  1043  	b = *attempt
  1044  	b.AttemptID = 1
  1045  	b.Route.FinalHop().MPP = record.NewMPP(
  1046  		info.Value, [32]byte{1},
  1047  	)
  1048  
  1049  	_, err = pControl.RegisterAttempt(info.PaymentIdentifier, &b)
  1050  	if err != ErrNonMPPayment {
  1051  		t.Fatalf("expected ErrNonMPPayment, got: %v", err)
  1052  	}
  1053  }
  1054  
  1055  // assertPaymentStatus retrieves the status of the payment referred to by hash
  1056  // and compares it with the expected state.
  1057  func assertPaymentStatus(t *testing.T, p *PaymentControl,
  1058  	hash lntypes.Hash, expStatus PaymentStatus) {
  1059  
  1060  	t.Helper()
  1061  
  1062  	payment, err := p.FetchPayment(hash)
  1063  	if expStatus == StatusUnknown && err == ErrPaymentNotInitiated {
  1064  		return
  1065  	}
  1066  	if err != nil {
  1067  		t.Fatal(err)
  1068  	}
  1069  
  1070  	if payment.Status != expStatus {
  1071  		t.Fatalf("payment status mismatch: expected %v, got %v",
  1072  			expStatus, payment.Status)
  1073  	}
  1074  }
  1075  
  1076  type htlcStatus struct {
  1077  	*HTLCAttemptInfo
  1078  	settle  *lntypes.Preimage
  1079  	failure *HTLCFailReason
  1080  }
  1081  
  1082  // assertPaymentInfo retrieves the payment referred to by hash and verifies the
  1083  // expected values.
  1084  func assertPaymentInfo(t *testing.T, p *PaymentControl, hash lntypes.Hash,
  1085  	c *PaymentCreationInfo, f *FailureReason, a *htlcStatus) {
  1086  
  1087  	t.Helper()
  1088  
  1089  	payment, err := p.FetchPayment(hash)
  1090  	if err != nil {
  1091  		t.Fatal(err)
  1092  	}
  1093  
  1094  	if !reflect.DeepEqual(payment.Info, c) {
  1095  		t.Fatalf("PaymentCreationInfos don't match: %v vs %v",
  1096  			spew.Sdump(payment.Info), spew.Sdump(c))
  1097  	}
  1098  
  1099  	if f != nil {
  1100  		if *payment.FailureReason != *f {
  1101  			t.Fatal("unexpected failure reason")
  1102  		}
  1103  	} else {
  1104  		if payment.FailureReason != nil {
  1105  			t.Fatal("unexpected failure reason")
  1106  		}
  1107  	}
  1108  
  1109  	if a == nil {
  1110  		if len(payment.HTLCs) > 0 {
  1111  			t.Fatal("expected no htlcs")
  1112  		}
  1113  		return
  1114  	}
  1115  
  1116  	htlc := payment.HTLCs[a.AttemptID]
  1117  	if err := assertRouteEqual(&htlc.Route, &a.Route); err != nil {
  1118  		t.Fatal("routes do not match")
  1119  	}
  1120  
  1121  	if htlc.AttemptID != a.AttemptID {
  1122  		t.Fatalf("unnexpected attempt ID %v, expected %v",
  1123  			htlc.AttemptID, a.AttemptID)
  1124  	}
  1125  
  1126  	if a.failure != nil {
  1127  		if htlc.Failure == nil {
  1128  			t.Fatalf("expected HTLC to be failed")
  1129  		}
  1130  
  1131  		if htlc.Failure.Reason != *a.failure {
  1132  			t.Fatalf("expected HTLC failure %v, had %v",
  1133  				*a.failure, htlc.Failure.Reason)
  1134  		}
  1135  	} else if htlc.Failure != nil {
  1136  		t.Fatalf("expected no HTLC failure")
  1137  	}
  1138  
  1139  	if a.settle != nil {
  1140  		if htlc.Settle.Preimage != *a.settle {
  1141  			t.Fatalf("Preimages don't match: %x vs %x",
  1142  				htlc.Settle.Preimage, a.settle)
  1143  		}
  1144  	} else if htlc.Settle != nil {
  1145  		t.Fatal("expected no settle info")
  1146  	}
  1147  }
  1148  
  1149  // fetchPaymentIndexEntry gets the payment hash for the sequence number provided
  1150  // from our payment indexes bucket.
  1151  func fetchPaymentIndexEntry(_ *testing.T, p *PaymentControl,
  1152  	sequenceNumber uint64) (*lntypes.Hash, error) {
  1153  
  1154  	var hash lntypes.Hash
  1155  
  1156  	if err := kvdb.View(p.db, func(tx walletdb.ReadTx) error {
  1157  		indexBucket := tx.ReadBucket(paymentsIndexBucket)
  1158  		key := make([]byte, 8)
  1159  		byteOrder.PutUint64(key, sequenceNumber)
  1160  
  1161  		indexValue := indexBucket.Get(key)
  1162  		if indexValue == nil {
  1163  			return errNoSequenceNrIndex
  1164  		}
  1165  
  1166  		r := bytes.NewReader(indexValue)
  1167  
  1168  		var err error
  1169  		hash, err = deserializePaymentIndex(r)
  1170  		return err
  1171  	}, func() {
  1172  		hash = lntypes.Hash{}
  1173  	}); err != nil {
  1174  		return nil, err
  1175  	}
  1176  
  1177  	return &hash, nil
  1178  }
  1179  
  1180  // assertPaymentIndex looks up the index for a payment in the db and checks
  1181  // that its payment hash matches the expected hash passed in.
  1182  func assertPaymentIndex(t *testing.T, p *PaymentControl,
  1183  	expectedHash lntypes.Hash) {
  1184  
  1185  	// Lookup the payment so that we have its sequence number and check
  1186  	// that is has correctly been indexed in the payment indexes bucket.
  1187  	pmt, err := p.FetchPayment(expectedHash)
  1188  	require.NoError(t, err)
  1189  
  1190  	hash, err := fetchPaymentIndexEntry(t, p, pmt.SequenceNum)
  1191  	require.NoError(t, err)
  1192  	assert.Equal(t, expectedHash, *hash)
  1193  }
  1194  
  1195  // assertNoIndex checks that an index for the sequence number provided does not
  1196  // exist.
  1197  func assertNoIndex(t *testing.T, p *PaymentControl, seqNr uint64) {
  1198  	_, err := fetchPaymentIndexEntry(t, p, seqNr)
  1199  	require.Equal(t, errNoSequenceNrIndex, err)
  1200  }
  1201  
  1202  // payment is a helper structure that holds basic information on a test payment,
  1203  // such as the payment id, the status and the total number of HTLCs attempted.
  1204  type payment struct {
  1205  	id     lntypes.Hash
  1206  	status PaymentStatus
  1207  	htlcs  int
  1208  }
  1209  
  1210  // createTestPayments registers payments depending on the provided statuses in
  1211  // the payments slice. Each payment will receive one failed HTLC and another
  1212  // HTLC depending on the final status of the payment provided.
  1213  func createTestPayments(t *testing.T, p *PaymentControl, payments []*payment) {
  1214  	attemptID := uint64(0)
  1215  
  1216  	for i := 0; i < len(payments); i++ {
  1217  		info, attempt, preimg, err := genInfo()
  1218  		require.NoError(t, err, "unable to generate htlc message")
  1219  
  1220  		// Set the payment id accordingly in the payments slice.
  1221  		payments[i].id = info.PaymentIdentifier
  1222  
  1223  		attempt.AttemptID = attemptID
  1224  		attemptID++
  1225  
  1226  		// Init the payment.
  1227  		err = p.InitPayment(info.PaymentIdentifier, info)
  1228  		require.NoError(t, err, "unable to send htlc message")
  1229  
  1230  		// Register and fail the first attempt for all payments.
  1231  		_, err = p.RegisterAttempt(info.PaymentIdentifier, attempt)
  1232  		require.NoError(t, err, "unable to send htlc message")
  1233  
  1234  		htlcFailure := HTLCFailUnreadable
  1235  		_, err = p.FailAttempt(
  1236  			info.PaymentIdentifier, attempt.AttemptID,
  1237  			&HTLCFailInfo{
  1238  				Reason: htlcFailure,
  1239  			},
  1240  		)
  1241  		require.NoError(t, err, "unable to fail htlc")
  1242  
  1243  		// Increase the HTLC counter in the payments slice for the
  1244  		// failed attempt.
  1245  		payments[i].htlcs++
  1246  
  1247  		// Depending on the test case, fail or succeed the next
  1248  		// attempt.
  1249  		attempt.AttemptID = attemptID
  1250  		attemptID++
  1251  
  1252  		_, err = p.RegisterAttempt(info.PaymentIdentifier, attempt)
  1253  		require.NoError(t, err, "unable to send htlc message")
  1254  
  1255  		switch payments[i].status {
  1256  
  1257  		// Fail the attempt and the payment overall.
  1258  		case StatusFailed:
  1259  			htlcFailure := HTLCFailUnreadable
  1260  			_, err = p.FailAttempt(
  1261  				info.PaymentIdentifier, attempt.AttemptID,
  1262  				&HTLCFailInfo{
  1263  					Reason: htlcFailure,
  1264  				},
  1265  			)
  1266  			require.NoError(t, err, "unable to fail htlc")
  1267  
  1268  			failReason := FailureReasonNoRoute
  1269  			_, err = p.Fail(info.PaymentIdentifier,
  1270  				failReason)
  1271  			require.NoError(t, err, "unable to fail payment hash")
  1272  
  1273  		// Settle the attempt
  1274  		case StatusSucceeded:
  1275  			_, err := p.SettleAttempt(
  1276  				info.PaymentIdentifier, attempt.AttemptID,
  1277  				&HTLCSettleInfo{
  1278  					Preimage: preimg,
  1279  				},
  1280  			)
  1281  			require.NoError(t, err, "no error should have been "+
  1282  				"received from settling a htlc attempt")
  1283  
  1284  		// We leave the attempt in-flight by doing nothing.
  1285  		case StatusInFlight:
  1286  		}
  1287  
  1288  		// Increase the HTLC counter in the payments slice for any
  1289  		// attempt above.
  1290  		payments[i].htlcs++
  1291  	}
  1292  }
  1293  
  1294  // assertPayments is a helper function that given a slice of payment and
  1295  // indices for the slice asserts that exactly the same payments in the
  1296  // slice for the provided indices exist when fetching payments from the
  1297  // database.
  1298  func assertPayments(t *testing.T, db *DB, payments []*payment) {
  1299  	t.Helper()
  1300  
  1301  	dbPayments, err := db.FetchPayments()
  1302  	require.NoError(t, err, "could not fetch payments from db")
  1303  
  1304  	// Make sure that the number of fetched payments is the same
  1305  	// as expected.
  1306  	require.Len(t, dbPayments, len(payments), "unexpected number of payments")
  1307  
  1308  	// Convert fetched payments of type MPPayment to our helper structure.
  1309  	p := make([]*payment, len(dbPayments))
  1310  	for i, dbPayment := range dbPayments {
  1311  		p[i] = &payment{
  1312  			id:     dbPayment.Info.PaymentIdentifier,
  1313  			status: dbPayment.Status,
  1314  			htlcs:  len(dbPayment.HTLCs),
  1315  		}
  1316  	}
  1317  
  1318  	// Check that each payment we want to assert exists in the database.
  1319  	require.Equal(t, payments, p)
  1320  }