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

     1  package channeldb
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/rand"
     6  	"fmt"
     7  	"math"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/decred/dcrlnd/clock"
    12  	"github.com/decred/dcrlnd/feature"
    13  	"github.com/decred/dcrlnd/lntypes"
    14  	"github.com/decred/dcrlnd/lnwire"
    15  	"github.com/decred/dcrlnd/record"
    16  	"github.com/decred/dcrlnd/tlv"
    17  	"github.com/stretchr/testify/require"
    18  )
    19  
    20  var (
    21  	emptyFeatures = lnwire.NewFeatureVector(nil, lnwire.Features)
    22  	ampFeatures   = lnwire.NewFeatureVector(
    23  		lnwire.NewRawFeatureVector(
    24  			lnwire.TLVOnionPayloadOptional,
    25  			lnwire.PaymentAddrOptional,
    26  			lnwire.AMPRequired,
    27  		),
    28  		lnwire.Features,
    29  	)
    30  	testNow = time.Unix(1, 0)
    31  )
    32  
    33  func randInvoice(value lnwire.MilliAtom) (*Invoice, error) {
    34  	var (
    35  		pre     lntypes.Preimage
    36  		payAddr [32]byte
    37  	)
    38  	if _, err := rand.Read(pre[:]); err != nil {
    39  		return nil, err
    40  	}
    41  	if _, err := rand.Read(payAddr[:]); err != nil {
    42  		return nil, err
    43  	}
    44  
    45  	i := &Invoice{
    46  		CreationDate: testNow,
    47  		Terms: ContractTerm{
    48  			Expiry:          4000,
    49  			PaymentPreimage: &pre,
    50  			PaymentAddr:     payAddr,
    51  			Value:           value,
    52  			Features:        emptyFeatures,
    53  		},
    54  		Htlcs:    map[CircuitKey]*InvoiceHTLC{},
    55  		AMPState: map[SetID]InvoiceStateAMP{},
    56  	}
    57  	i.Memo = []byte("memo")
    58  
    59  	// Create a random byte slice of MaxPaymentRequestSize bytes to be used
    60  	// as a dummy paymentrequest, and  determine if it should be set based
    61  	// on one of the random bytes.
    62  	var r [MaxPaymentRequestSize]byte
    63  	if _, err := rand.Read(r[:]); err != nil {
    64  		return nil, err
    65  	}
    66  	if r[0]&1 == 0 {
    67  		i.PaymentRequest = r[:]
    68  	} else {
    69  		i.PaymentRequest = []byte("")
    70  	}
    71  
    72  	return i, nil
    73  }
    74  
    75  // settleTestInvoice settles a test invoice.
    76  func settleTestInvoice(invoice *Invoice, settleIndex uint64) {
    77  	invoice.SettleDate = testNow
    78  	invoice.AmtPaid = invoice.Terms.Value
    79  	invoice.State = ContractSettled
    80  	invoice.Htlcs[CircuitKey{}] = &InvoiceHTLC{
    81  		Amt:           invoice.Terms.Value,
    82  		AcceptTime:    testNow,
    83  		ResolveTime:   testNow,
    84  		State:         HtlcStateSettled,
    85  		CustomRecords: make(record.CustomSet),
    86  	}
    87  	invoice.SettleIndex = settleIndex
    88  }
    89  
    90  // Tests that pending invoices are those which are either in ContractOpen or
    91  // in ContractAccepted state.
    92  func TestInvoiceIsPending(t *testing.T) {
    93  	contractStates := []ContractState{
    94  		ContractOpen, ContractSettled, ContractCanceled, ContractAccepted,
    95  	}
    96  
    97  	for _, state := range contractStates {
    98  		invoice := Invoice{
    99  			State: state,
   100  		}
   101  
   102  		// We expect that an invoice is pending if it's either in ContractOpen
   103  		// or ContractAccepted state.
   104  		pending := (state == ContractOpen || state == ContractAccepted)
   105  
   106  		if invoice.IsPending() != pending {
   107  			t.Fatalf("expected pending: %v, got: %v, invoice: %v",
   108  				pending, invoice.IsPending(), invoice)
   109  		}
   110  	}
   111  }
   112  
   113  type invWorkflowTest struct {
   114  	name         string
   115  	queryPayHash bool
   116  	queryPayAddr bool
   117  }
   118  
   119  var invWorkflowTests = []invWorkflowTest{
   120  	{
   121  		name:         "unknown",
   122  		queryPayHash: false,
   123  		queryPayAddr: false,
   124  	},
   125  	{
   126  		name:         "only payhash known",
   127  		queryPayHash: true,
   128  		queryPayAddr: false,
   129  	},
   130  	{
   131  		name:         "payaddr and payhash known",
   132  		queryPayHash: true,
   133  		queryPayAddr: true,
   134  	},
   135  }
   136  
   137  // TestInvoiceWorkflow asserts the basic process of inserting, fetching, and
   138  // updating an invoice. We assert that the flow is successful using when
   139  // querying with various combinations of payment hash and payment address.
   140  func TestInvoiceWorkflow(t *testing.T) {
   141  	t.Parallel()
   142  
   143  	for _, test := range invWorkflowTests {
   144  		test := test
   145  		t.Run(test.name, func(t *testing.T) {
   146  			testInvoiceWorkflow(t, test)
   147  		})
   148  	}
   149  }
   150  
   151  func testInvoiceWorkflow(t *testing.T, test invWorkflowTest) {
   152  	db, cleanUp, err := MakeTestDB()
   153  	defer cleanUp()
   154  	if err != nil {
   155  		t.Fatalf("unable to make test db: %v", err)
   156  	}
   157  
   158  	// Create a fake invoice which we'll use several times in the tests
   159  	// below.
   160  	fakeInvoice, err := randInvoice(10000)
   161  	if err != nil {
   162  		t.Fatalf("unable to create invoice: %v", err)
   163  	}
   164  	invPayHash := fakeInvoice.Terms.PaymentPreimage.Hash()
   165  
   166  	// Select the payment hash and payment address we will use to lookup or
   167  	// update the invoice for the remainder of the test.
   168  	var (
   169  		payHash lntypes.Hash
   170  		payAddr *[32]byte
   171  		ref     InvoiceRef
   172  	)
   173  	switch {
   174  	case test.queryPayHash && test.queryPayAddr:
   175  		payHash = invPayHash
   176  		payAddr = &fakeInvoice.Terms.PaymentAddr
   177  		ref = InvoiceRefByHashAndAddr(payHash, *payAddr)
   178  	case test.queryPayHash:
   179  		payHash = invPayHash
   180  		ref = InvoiceRefByHash(payHash)
   181  	}
   182  
   183  	// Add the invoice to the database, this should succeed as there aren't
   184  	// any existing invoices within the database with the same payment
   185  	// hash.
   186  	if _, err := db.AddInvoice(fakeInvoice, invPayHash); err != nil {
   187  		t.Fatalf("unable to find invoice: %v", err)
   188  	}
   189  
   190  	// Attempt to retrieve the invoice which was just added to the
   191  	// database. It should be found, and the invoice returned should be
   192  	// identical to the one created above.
   193  	dbInvoice, err := db.LookupInvoice(ref)
   194  	if !test.queryPayAddr && !test.queryPayHash {
   195  		if err != ErrInvoiceNotFound {
   196  			t.Fatalf("invoice should not exist: %v", err)
   197  		}
   198  		return
   199  	}
   200  
   201  	require.Equal(t,
   202  		*fakeInvoice, dbInvoice,
   203  		"invoice fetched from db doesn't match original",
   204  	)
   205  
   206  	// The add index of the invoice retrieved from the database should now
   207  	// be fully populated. As this is the first index written to the DB,
   208  	// the addIndex should be 1.
   209  	if dbInvoice.AddIndex != 1 {
   210  		t.Fatalf("wrong add index: expected %v, got %v", 1,
   211  			dbInvoice.AddIndex)
   212  	}
   213  
   214  	// Settle the invoice, the version retrieved from the database should
   215  	// now have the settled bit toggle to true and a non-default
   216  	// SettledDate
   217  	payAmt := fakeInvoice.Terms.Value * 2
   218  	_, err = db.UpdateInvoice(ref, nil, getUpdateInvoice(payAmt))
   219  	if err != nil {
   220  		t.Fatalf("unable to settle invoice: %v", err)
   221  	}
   222  	dbInvoice2, err := db.LookupInvoice(ref)
   223  	if err != nil {
   224  		t.Fatalf("unable to fetch invoice: %v", err)
   225  	}
   226  	if dbInvoice2.State != ContractSettled {
   227  		t.Fatalf("invoice should now be settled but isn't")
   228  	}
   229  	if dbInvoice2.SettleDate.IsZero() {
   230  		t.Fatalf("invoice should have non-zero SettledDate but isn't")
   231  	}
   232  
   233  	// Our 2x payment should be reflected, and also the settle index of 1
   234  	// should also have been committed for this index.
   235  	if dbInvoice2.AmtPaid != payAmt {
   236  		t.Fatalf("wrong amt paid: expected %v, got %v", payAmt,
   237  			dbInvoice2.AmtPaid)
   238  	}
   239  	if dbInvoice2.SettleIndex != 1 {
   240  		t.Fatalf("wrong settle index: expected %v, got %v", 1,
   241  			dbInvoice2.SettleIndex)
   242  	}
   243  
   244  	// Attempt to insert generated above again, this should fail as
   245  	// duplicates are rejected by the processing logic.
   246  	if _, err := db.AddInvoice(fakeInvoice, payHash); err != ErrDuplicateInvoice {
   247  		t.Fatalf("invoice insertion should fail due to duplication, "+
   248  			"instead %v", err)
   249  	}
   250  
   251  	// Attempt to look up a non-existent invoice, this should also fail but
   252  	// with a "not found" error.
   253  	var fakeHash [32]byte
   254  	fakeRef := InvoiceRefByHash(fakeHash)
   255  	_, err = db.LookupInvoice(fakeRef)
   256  	if err != ErrInvoiceNotFound {
   257  		t.Fatalf("lookup should have failed, instead %v", err)
   258  	}
   259  
   260  	// Add 10 random invoices.
   261  	const numInvoices = 10
   262  	amt := lnwire.NewMAtomsFromAtoms(1000)
   263  	invoices := make([]*Invoice, numInvoices+1)
   264  	invoices[0] = &dbInvoice2
   265  	for i := 1; i < len(invoices); i++ {
   266  		invoice, err := randInvoice(amt)
   267  		if err != nil {
   268  			t.Fatalf("unable to create invoice: %v", err)
   269  		}
   270  
   271  		hash := invoice.Terms.PaymentPreimage.Hash()
   272  		if _, err := db.AddInvoice(invoice, hash); err != nil {
   273  			t.Fatalf("unable to add invoice %v", err)
   274  		}
   275  
   276  		invoices[i] = invoice
   277  	}
   278  
   279  	// Perform a scan to collect all the active invoices.
   280  	query := InvoiceQuery{
   281  		IndexOffset:    0,
   282  		NumMaxInvoices: math.MaxUint64,
   283  		PendingOnly:    false,
   284  	}
   285  
   286  	response, err := db.QueryInvoices(query)
   287  	if err != nil {
   288  		t.Fatalf("invoice query failed: %v", err)
   289  	}
   290  
   291  	// The retrieve list of invoices should be identical as since we're
   292  	// using big endian, the invoices should be retrieved in ascending
   293  	// order (and the primary key should be incremented with each
   294  	// insertion).
   295  	for i := 0; i < len(invoices); i++ {
   296  		require.Equal(t,
   297  			*invoices[i], response.Invoices[i],
   298  			"retrieved invoice doesn't match",
   299  		)
   300  	}
   301  }
   302  
   303  // TestAddDuplicatePayAddr asserts that the payment addresses of inserted
   304  // invoices are unique.
   305  func TestAddDuplicatePayAddr(t *testing.T) {
   306  	db, cleanUp, err := MakeTestDB()
   307  	defer cleanUp()
   308  	require.NoError(t, err)
   309  
   310  	// Create two invoices with the same payment addr.
   311  	invoice1, err := randInvoice(1000)
   312  	require.NoError(t, err)
   313  
   314  	invoice2, err := randInvoice(20000)
   315  	require.NoError(t, err)
   316  	invoice2.Terms.PaymentAddr = invoice1.Terms.PaymentAddr
   317  
   318  	// First insert should succeed.
   319  	inv1Hash := invoice1.Terms.PaymentPreimage.Hash()
   320  	_, err = db.AddInvoice(invoice1, inv1Hash)
   321  	require.NoError(t, err)
   322  
   323  	// Second insert should fail with duplicate payment addr.
   324  	inv2Hash := invoice2.Terms.PaymentPreimage.Hash()
   325  	_, err = db.AddInvoice(invoice2, inv2Hash)
   326  	require.Error(t, err, ErrDuplicatePayAddr)
   327  }
   328  
   329  // TestAddDuplicateKeysendPayAddr asserts that we permit duplicate payment
   330  // addresses to be inserted if they are blank to support JIT legacy keysend
   331  // invoices.
   332  func TestAddDuplicateKeysendPayAddr(t *testing.T) {
   333  	db, cleanUp, err := MakeTestDB()
   334  	defer cleanUp()
   335  	require.NoError(t, err)
   336  
   337  	// Create two invoices with the same _blank_ payment addr.
   338  	invoice1, err := randInvoice(1000)
   339  	require.NoError(t, err)
   340  	invoice1.Terms.PaymentAddr = BlankPayAddr
   341  
   342  	invoice2, err := randInvoice(20000)
   343  	require.NoError(t, err)
   344  	invoice2.Terms.PaymentAddr = BlankPayAddr
   345  
   346  	// Inserting both should succeed without a duplicate payment address
   347  	// failure.
   348  	inv1Hash := invoice1.Terms.PaymentPreimage.Hash()
   349  	_, err = db.AddInvoice(invoice1, inv1Hash)
   350  	require.NoError(t, err)
   351  
   352  	inv2Hash := invoice2.Terms.PaymentPreimage.Hash()
   353  	_, err = db.AddInvoice(invoice2, inv2Hash)
   354  	require.NoError(t, err)
   355  
   356  	// Querying for each should succeed. Here we use hash+addr refs since
   357  	// the lookup will fail if the hash and addr point to different
   358  	// invoices, so if both succeed we can be assured they aren't included
   359  	// in the payment address index.
   360  	ref1 := InvoiceRefByHashAndAddr(inv1Hash, BlankPayAddr)
   361  	dbInv1, err := db.LookupInvoice(ref1)
   362  	require.NoError(t, err)
   363  	require.Equal(t, invoice1, &dbInv1)
   364  
   365  	ref2 := InvoiceRefByHashAndAddr(inv2Hash, BlankPayAddr)
   366  	dbInv2, err := db.LookupInvoice(ref2)
   367  	require.NoError(t, err)
   368  	require.Equal(t, invoice2, &dbInv2)
   369  }
   370  
   371  // TestFailInvoiceLookupMPPPayAddrOnly asserts that looking up a MPP invoice
   372  // that matches _only_ by payment address fails with ErrInvoiceNotFound. This
   373  // ensures that the HTLC's payment hash always matches the payment hash in the
   374  // returned invoice.
   375  func TestFailInvoiceLookupMPPPayAddrOnly(t *testing.T) {
   376  	db, cleanUp, err := MakeTestDB()
   377  	defer cleanUp()
   378  	require.NoError(t, err)
   379  
   380  	// Create and insert a random invoice.
   381  	invoice, err := randInvoice(1000)
   382  	require.NoError(t, err)
   383  
   384  	payHash := invoice.Terms.PaymentPreimage.Hash()
   385  	payAddr := invoice.Terms.PaymentAddr
   386  	_, err = db.AddInvoice(invoice, payHash)
   387  	require.NoError(t, err)
   388  
   389  	// Modify the queried payment hash to be invalid.
   390  	payHash[0] ^= 0x01
   391  
   392  	// Lookup the invoice by (invalid) payment hash and payment address. The
   393  	// lookup should fail since we require the payment hash to match for
   394  	// legacy/MPP invoices, as this guarantees that the preimage is valid
   395  	// for the given HTLC.
   396  	ref := InvoiceRefByHashAndAddr(payHash, payAddr)
   397  	_, err = db.LookupInvoice(ref)
   398  	require.Equal(t, ErrInvoiceNotFound, err)
   399  }
   400  
   401  // TestInvRefEquivocation asserts that retrieving or updating an invoice using
   402  // an equivocating InvoiceRef results in ErrInvRefEquivocation.
   403  func TestInvRefEquivocation(t *testing.T) {
   404  	db, cleanUp, err := MakeTestDB()
   405  	defer cleanUp()
   406  	require.NoError(t, err)
   407  
   408  	// Add two random invoices.
   409  	invoice1, err := randInvoice(1000)
   410  	require.NoError(t, err)
   411  
   412  	inv1Hash := invoice1.Terms.PaymentPreimage.Hash()
   413  	_, err = db.AddInvoice(invoice1, inv1Hash)
   414  	require.NoError(t, err)
   415  
   416  	invoice2, err := randInvoice(2000)
   417  	require.NoError(t, err)
   418  
   419  	inv2Hash := invoice2.Terms.PaymentPreimage.Hash()
   420  	_, err = db.AddInvoice(invoice2, inv2Hash)
   421  	require.NoError(t, err)
   422  
   423  	// Now, query using invoice 1's payment address, but invoice 2's payment
   424  	// hash. We expect an error since the invref points to multiple
   425  	// invoices.
   426  	ref := InvoiceRefByHashAndAddr(inv2Hash, invoice1.Terms.PaymentAddr)
   427  	_, err = db.LookupInvoice(ref)
   428  	require.Error(t, err, ErrInvRefEquivocation)
   429  
   430  	// The same error should be returned when updating an equivocating
   431  	// reference.
   432  	nop := func(_ *Invoice) (*InvoiceUpdateDesc, error) {
   433  		return nil, nil
   434  	}
   435  	_, err = db.UpdateInvoice(ref, nil, nop)
   436  	require.Error(t, err, ErrInvRefEquivocation)
   437  }
   438  
   439  // TestInvoiceCancelSingleHtlc tests that a single htlc can be canceled on the
   440  // invoice.
   441  func TestInvoiceCancelSingleHtlc(t *testing.T) {
   442  	t.Parallel()
   443  
   444  	db, cleanUp, err := MakeTestDB()
   445  	defer cleanUp()
   446  	if err != nil {
   447  		t.Fatalf("unable to make test db: %v", err)
   448  	}
   449  
   450  	preimage := lntypes.Preimage{1}
   451  	paymentHash := preimage.Hash()
   452  
   453  	testInvoice := &Invoice{
   454  		Htlcs: map[CircuitKey]*InvoiceHTLC{},
   455  		Terms: ContractTerm{
   456  			Value:           lnwire.NewMAtomsFromAtoms(10000),
   457  			Features:        emptyFeatures,
   458  			PaymentPreimage: &preimage,
   459  		},
   460  	}
   461  
   462  	if _, err := db.AddInvoice(testInvoice, paymentHash); err != nil {
   463  		t.Fatalf("unable to find invoice: %v", err)
   464  	}
   465  
   466  	// Accept an htlc on this invoice.
   467  	key := CircuitKey{ChanID: lnwire.NewShortChanIDFromInt(1), HtlcID: 4}
   468  	htlc := HtlcAcceptDesc{
   469  		Amt:           500,
   470  		CustomRecords: make(record.CustomSet),
   471  	}
   472  
   473  	ref := InvoiceRefByHash(paymentHash)
   474  	invoice, err := db.UpdateInvoice(ref, nil,
   475  		func(invoice *Invoice) (*InvoiceUpdateDesc, error) {
   476  			return &InvoiceUpdateDesc{
   477  				AddHtlcs: map[CircuitKey]*HtlcAcceptDesc{
   478  					key: &htlc,
   479  				},
   480  			}, nil
   481  		})
   482  	if err != nil {
   483  		t.Fatalf("unable to add invoice htlc: %v", err)
   484  	}
   485  	if len(invoice.Htlcs) != 1 {
   486  		t.Fatalf("expected the htlc to be added")
   487  	}
   488  	if invoice.Htlcs[key].State != HtlcStateAccepted {
   489  		t.Fatalf("expected htlc in state accepted")
   490  	}
   491  
   492  	// Cancel the htlc again.
   493  	invoice, err = db.UpdateInvoice(ref, nil,
   494  		func(invoice *Invoice) (*InvoiceUpdateDesc, error) {
   495  			return &InvoiceUpdateDesc{
   496  				CancelHtlcs: map[CircuitKey]struct{}{
   497  					key: {},
   498  				},
   499  			}, nil
   500  		})
   501  	if err != nil {
   502  		t.Fatalf("unable to cancel htlc: %v", err)
   503  	}
   504  	if len(invoice.Htlcs) != 1 {
   505  		t.Fatalf("expected the htlc to be present")
   506  	}
   507  	if invoice.Htlcs[key].State != HtlcStateCanceled {
   508  		t.Fatalf("expected htlc in state canceled")
   509  	}
   510  }
   511  
   512  // TestInvoiceCancelSingleHtlcAMP tests that it's possible to cancel a single
   513  // invoice of an AMP HTLC across multiple set IDs, and also have that update
   514  // the amount paid and other related fields as well.
   515  func TestInvoiceCancelSingleHtlcAMP(t *testing.T) {
   516  	t.Parallel()
   517  
   518  	db, cleanUp, err := MakeTestDB(OptionClock(testClock))
   519  	defer cleanUp()
   520  	require.NoError(t, err, "unable to make test db: %v", err)
   521  
   522  	// We'll start out by creating an invoice and writing it to the DB.
   523  	amt := lnwire.NewMAtomsFromAtoms(1000)
   524  	invoice, err := randInvoice(amt)
   525  	require.Nil(t, err)
   526  
   527  	// Set AMP-specific features so that we can settle with HTLC-level
   528  	// preimages.
   529  	invoice.Terms.Features = ampFeatures
   530  
   531  	preimage := *invoice.Terms.PaymentPreimage
   532  	payHash := preimage.Hash()
   533  	_, err = db.AddInvoice(invoice, payHash)
   534  	require.Nil(t, err)
   535  
   536  	// Add two HTLC sets, one with one HTLC and the other with two.
   537  	setID1 := &[32]byte{1}
   538  	setID2 := &[32]byte{2}
   539  
   540  	ref := InvoiceRefByHashAndAddr(payHash, invoice.Terms.PaymentAddr)
   541  
   542  	// The first set ID with a single HTLC added.
   543  	_, err = db.UpdateInvoice(
   544  		ref, (*SetID)(setID1), updateAcceptAMPHtlc(0, amt, setID1, true),
   545  	)
   546  	require.Nil(t, err)
   547  
   548  	// The second set ID with two HTLCs added.
   549  	_, err = db.UpdateInvoice(
   550  		ref, (*SetID)(setID2), updateAcceptAMPHtlc(1, amt, setID2, true),
   551  	)
   552  	require.Nil(t, err)
   553  	dbInvoice, err := db.UpdateInvoice(
   554  		ref, (*SetID)(setID2), updateAcceptAMPHtlc(2, amt, setID2, true),
   555  	)
   556  	require.Nil(t, err)
   557  
   558  	// At this point, we should detect that 3k satoshis total has been
   559  	// paid.
   560  	require.Equal(t, dbInvoice.AmtPaid, amt*3)
   561  
   562  	// Now we'll cancel a single invoice, and assert that the amount paid
   563  	// is decremented, and the state for that HTLC set reflects that is
   564  	// been cancelled.
   565  	_, err = db.UpdateInvoice(ref, (*SetID)(setID1),
   566  		func(invoice *Invoice) (*InvoiceUpdateDesc, error) {
   567  			return &InvoiceUpdateDesc{
   568  				CancelHtlcs: map[CircuitKey]struct{}{
   569  					{HtlcID: 0}: {},
   570  				},
   571  				SetID: (*SetID)(setID1),
   572  			}, nil
   573  		})
   574  	if err != nil {
   575  		t.Fatalf("unable to cancel htlc: %v", err)
   576  	}
   577  
   578  	freshInvoice, err := db.LookupInvoice(ref)
   579  	require.Nil(t, err)
   580  	dbInvoice = &freshInvoice
   581  
   582  	// The amount paid should reflect that an invoice was cancelled.
   583  	require.Equal(t, dbInvoice.AmtPaid, amt*2)
   584  
   585  	// The HTLC and AMP state should also show that only one HTLC set is
   586  	// left.
   587  	invoice.State = ContractOpen
   588  	invoice.AmtPaid = 2 * amt
   589  	invoice.SettleDate = dbInvoice.SettleDate
   590  	invoice.Htlcs = map[CircuitKey]*InvoiceHTLC{
   591  		{HtlcID: 0}: makeAMPInvoiceHTLC(amt, *setID1, payHash, &preimage),
   592  		{HtlcID: 1}: makeAMPInvoiceHTLC(amt, *setID2, payHash, &preimage),
   593  		{HtlcID: 2}: makeAMPInvoiceHTLC(amt, *setID2, payHash, &preimage),
   594  	}
   595  	invoice.AMPState[*setID1] = InvoiceStateAMP{
   596  		State: HtlcStateCanceled,
   597  		InvoiceKeys: map[CircuitKey]struct{}{
   598  			{HtlcID: 0}: {},
   599  		},
   600  	}
   601  	invoice.AMPState[*setID2] = InvoiceStateAMP{
   602  		State:   HtlcStateAccepted,
   603  		AmtPaid: amt * 2,
   604  		InvoiceKeys: map[CircuitKey]struct{}{
   605  			{HtlcID: 1}: {},
   606  			{HtlcID: 2}: {},
   607  		},
   608  	}
   609  
   610  	invoice.Htlcs[CircuitKey{HtlcID: 0}].State = HtlcStateCanceled
   611  	invoice.Htlcs[CircuitKey{HtlcID: 0}].ResolveTime = time.Unix(1, 0)
   612  
   613  	require.Equal(t, invoice, dbInvoice)
   614  
   615  	// Next, we'll cancel the _other_ HTLCs active, but we'll do them one
   616  	// by one.
   617  	_, err = db.UpdateInvoice(ref, (*SetID)(setID2),
   618  		func(invoice *Invoice) (*InvoiceUpdateDesc, error) {
   619  			return &InvoiceUpdateDesc{
   620  				CancelHtlcs: map[CircuitKey]struct{}{
   621  					{HtlcID: 1}: {},
   622  				},
   623  				SetID: (*SetID)(setID2),
   624  			}, nil
   625  		})
   626  	if err != nil {
   627  		t.Fatalf("unable to cancel htlc: %v", err)
   628  	}
   629  
   630  	freshInvoice, err = db.LookupInvoice(ref)
   631  	require.Nil(t, err)
   632  	dbInvoice = &freshInvoice
   633  
   634  	invoice.Htlcs[CircuitKey{HtlcID: 1}].State = HtlcStateCanceled
   635  	invoice.Htlcs[CircuitKey{HtlcID: 1}].ResolveTime = time.Unix(1, 0)
   636  	invoice.AmtPaid = amt
   637  
   638  	ampState := invoice.AMPState[*setID2]
   639  	ampState.State = HtlcStateCanceled
   640  	ampState.AmtPaid = amt
   641  	invoice.AMPState[*setID2] = ampState
   642  
   643  	require.Equal(t, invoice, dbInvoice)
   644  
   645  	// Now we'll cancel the final HTLC, which should cause all the active
   646  	// HTLCs to transition to the cancelled state.
   647  	_, err = db.UpdateInvoice(ref, (*SetID)(setID2),
   648  		func(invoice *Invoice) (*InvoiceUpdateDesc, error) {
   649  			return &InvoiceUpdateDesc{
   650  				CancelHtlcs: map[CircuitKey]struct{}{
   651  					{HtlcID: 2}: {},
   652  				},
   653  				SetID: (*SetID)(setID2),
   654  			}, nil
   655  		})
   656  	if err != nil {
   657  		t.Fatalf("unable to cancel htlc: %v", err)
   658  	}
   659  
   660  	freshInvoice, err = db.LookupInvoice(ref)
   661  	require.Nil(t, err)
   662  	dbInvoice = &freshInvoice
   663  
   664  	ampState = invoice.AMPState[*setID2]
   665  	ampState.AmtPaid = 0
   666  	invoice.AMPState[*setID2] = ampState
   667  
   668  	invoice.Htlcs[CircuitKey{HtlcID: 2}].State = HtlcStateCanceled
   669  	invoice.Htlcs[CircuitKey{HtlcID: 2}].ResolveTime = time.Unix(1, 0)
   670  	invoice.AmtPaid = 0
   671  
   672  	require.Equal(t, invoice, dbInvoice)
   673  }
   674  
   675  // TestInvoiceTimeSeries tests that newly added invoices invoices, as well as
   676  // settled invoices are added to the database are properly placed in the add
   677  // add or settle index which serves as an event time series.
   678  func TestInvoiceAddTimeSeries(t *testing.T) {
   679  	t.Parallel()
   680  
   681  	db, cleanUp, err := MakeTestDB(OptionClock(testClock))
   682  	defer cleanUp()
   683  	if err != nil {
   684  		t.Fatalf("unable to make test db: %v", err)
   685  	}
   686  
   687  	_, err = db.InvoicesAddedSince(0)
   688  	require.NoError(t, err)
   689  
   690  	// We'll start off by creating 20 random invoices, and inserting them
   691  	// into the database.
   692  	const numInvoices = 20
   693  	amt := lnwire.NewMAtomsFromAtoms(1000)
   694  	invoices := make([]Invoice, numInvoices)
   695  	for i := 0; i < len(invoices); i++ {
   696  		invoice, err := randInvoice(amt)
   697  		if err != nil {
   698  			t.Fatalf("unable to create invoice: %v", err)
   699  		}
   700  
   701  		paymentHash := invoice.Terms.PaymentPreimage.Hash()
   702  
   703  		if _, err := db.AddInvoice(invoice, paymentHash); err != nil {
   704  			t.Fatalf("unable to add invoice %v", err)
   705  		}
   706  
   707  		invoices[i] = *invoice
   708  	}
   709  
   710  	// With the invoices constructed, we'll now create a series of queries
   711  	// that we'll use to assert expected return values of
   712  	// InvoicesAddedSince.
   713  	addQueries := []struct {
   714  		sinceAddIndex uint64
   715  
   716  		resp []Invoice
   717  	}{
   718  		// If we specify a value of zero, we shouldn't get any invoices
   719  		// back.
   720  		{
   721  			sinceAddIndex: 0,
   722  		},
   723  
   724  		// If we specify a value well beyond the number of inserted
   725  		// invoices, we shouldn't get any invoices back.
   726  		{
   727  			sinceAddIndex: 99999999,
   728  		},
   729  
   730  		// Using an index of 1 should result in all values, but the
   731  		// first one being returned.
   732  		{
   733  			sinceAddIndex: 1,
   734  			resp:          invoices[1:],
   735  		},
   736  
   737  		// If we use an index of 10, then we should retrieve the
   738  		// reaming 10 invoices.
   739  		{
   740  			sinceAddIndex: 10,
   741  			resp:          invoices[10:],
   742  		},
   743  	}
   744  
   745  	for i, query := range addQueries {
   746  		resp, err := db.InvoicesAddedSince(query.sinceAddIndex)
   747  		if err != nil {
   748  			t.Fatalf("unable to query: %v", err)
   749  		}
   750  
   751  		require.Equal(t, len(query.resp), len(resp))
   752  
   753  		for j := 0; j < len(query.resp); j++ {
   754  			require.Equal(t,
   755  				query.resp[j], resp[j],
   756  				fmt.Sprintf("test: #%v, item: #%v", i, j),
   757  			)
   758  		}
   759  	}
   760  
   761  	_, err = db.InvoicesSettledSince(0)
   762  	require.NoError(t, err)
   763  
   764  	var settledInvoices []Invoice
   765  	var settleIndex uint64 = 1
   766  	// We'll now only settle the latter half of each of those invoices.
   767  	for i := 10; i < len(invoices); i++ {
   768  		invoice := &invoices[i]
   769  
   770  		paymentHash := invoice.Terms.PaymentPreimage.Hash()
   771  
   772  		ref := InvoiceRefByHash(paymentHash)
   773  		_, err := db.UpdateInvoice(
   774  			ref, nil, getUpdateInvoice(invoice.Terms.Value),
   775  		)
   776  		if err != nil {
   777  			t.Fatalf("unable to settle invoice: %v", err)
   778  		}
   779  
   780  		// Create the settled invoice for the expectation set.
   781  		settleTestInvoice(invoice, settleIndex)
   782  		settleIndex++
   783  
   784  		settledInvoices = append(settledInvoices, *invoice)
   785  	}
   786  
   787  	// We'll now prepare an additional set of queries to ensure the settle
   788  	// time series has properly been maintained in the database.
   789  	settleQueries := []struct {
   790  		sinceSettleIndex uint64
   791  
   792  		resp []Invoice
   793  	}{
   794  		// If we specify a value of zero, we shouldn't get any settled
   795  		// invoices back.
   796  		{
   797  			sinceSettleIndex: 0,
   798  		},
   799  
   800  		// If we specify a value well beyond the number of settled
   801  		// invoices, we shouldn't get any invoices back.
   802  		{
   803  			sinceSettleIndex: 99999999,
   804  		},
   805  
   806  		// Using an index of 1 should result in the final 10 invoices
   807  		// being returned, as we only settled those.
   808  		{
   809  			sinceSettleIndex: 1,
   810  			resp:             settledInvoices[1:],
   811  		},
   812  	}
   813  
   814  	for i, query := range settleQueries {
   815  		resp, err := db.InvoicesSettledSince(query.sinceSettleIndex)
   816  		if err != nil {
   817  			t.Fatalf("unable to query: %v", err)
   818  		}
   819  
   820  		require.Equal(t, len(query.resp), len(resp))
   821  
   822  		for j := 0; j < len(query.resp); j++ {
   823  			require.Equal(t,
   824  				query.resp[j], resp[j],
   825  				fmt.Sprintf("test: #%v, item: #%v", i, j),
   826  			)
   827  		}
   828  	}
   829  }
   830  
   831  // TestSettleIndexAmpPayments tests that repeated settles of the same invoice
   832  // end up properly adding entries to the settle index, and the
   833  // InvoicesSettledSince will emit a "projected" version of the invoice w/
   834  // _just_ that HTLC information.
   835  func TestSettleIndexAmpPayments(t *testing.T) {
   836  	t.Parallel()
   837  
   838  	testClock := clock.NewTestClock(testNow)
   839  	db, cleanUp, err := MakeTestDB(OptionClock(testClock))
   840  	defer cleanUp()
   841  	require.Nil(t, err)
   842  
   843  	// First, we'll make a sample invoice that'll be paid to several times
   844  	// below.
   845  	amt := lnwire.NewMAtomsFromAtoms(1000)
   846  	testInvoice, err := randInvoice(amt)
   847  	require.Nil(t, err)
   848  	testInvoice.Terms.Features = ampFeatures
   849  
   850  	// Add the invoice to the DB, we use a dummy payment hash here but the
   851  	// invoice will have a valid payment address set.
   852  	preimage := *testInvoice.Terms.PaymentPreimage
   853  	payHash := preimage.Hash()
   854  	_, err = db.AddInvoice(testInvoice, payHash)
   855  	require.Nil(t, err)
   856  
   857  	// Now that we have the invoice, we'll simulate 3 different HTLC sets
   858  	// being attached to the invoice. These represent 3 different
   859  	// concurrent payments.
   860  	setID1 := &[32]byte{1}
   861  	setID2 := &[32]byte{2}
   862  	setID3 := &[32]byte{3}
   863  
   864  	ref := InvoiceRefByHashAndAddr(payHash, testInvoice.Terms.PaymentAddr)
   865  	_, err = db.UpdateInvoice(
   866  		ref, (*SetID)(setID1), updateAcceptAMPHtlc(1, amt, setID1, true),
   867  	)
   868  	require.Nil(t, err)
   869  	_, err = db.UpdateInvoice(
   870  		ref, (*SetID)(setID2), updateAcceptAMPHtlc(2, amt, setID2, true),
   871  	)
   872  	require.Nil(t, err)
   873  	_, err = db.UpdateInvoice(
   874  		ref, (*SetID)(setID3), updateAcceptAMPHtlc(3, amt, setID3, true),
   875  	)
   876  	require.Nil(t, err)
   877  
   878  	// Now that the invoices have been accepted, we'll exercise the
   879  	// behavior of the LookupInvoice call that allows us to modify exactly
   880  	// how we query for invoices.
   881  	//
   882  	// First, we'll query for the invoice with just the payment addr, but
   883  	// specify no HTLcs are to be included.
   884  	refNoHtlcs := InvoiceRefByAddrBlankHtlc(testInvoice.Terms.PaymentAddr)
   885  	invoiceNoHTLCs, err := db.LookupInvoice(refNoHtlcs)
   886  	require.Nil(t, err)
   887  
   888  	require.Equal(t, 0, len(invoiceNoHTLCs.Htlcs))
   889  
   890  	// We'll now look up the HTLCs based on the individual setIDs added
   891  	// above.
   892  	for i, setID := range []*[32]byte{setID1, setID2, setID3} {
   893  		refFiltered := InvoiceRefBySetIDFiltered(*setID)
   894  		invoiceFiltered, err := db.LookupInvoice(refFiltered)
   895  		require.Nil(t, err)
   896  
   897  		// Only a single HTLC should be present.
   898  		require.Equal(t, 1, len(invoiceFiltered.Htlcs))
   899  
   900  		// The set ID for the HTLC should match the queried set ID.
   901  		key := CircuitKey{HtlcID: uint64(i + 1)}
   902  		htlc := invoiceFiltered.Htlcs[key]
   903  		require.Equal(t, *setID, htlc.AMP.Record.SetID())
   904  
   905  		// The HTLC should show that it's in the accepted state.
   906  		require.Equal(t, htlc.State, HtlcStateAccepted)
   907  	}
   908  
   909  	// Now that we know the invoices are in the proper state, we'll settle
   910  	// them on by one in distinct updates.
   911  	_, err = db.UpdateInvoice(
   912  		ref, (*SetID)(setID1),
   913  		getUpdateInvoiceAMPSettle(
   914  			setID1, preimage, CircuitKey{HtlcID: 1},
   915  		),
   916  	)
   917  	require.Nil(t, err)
   918  	_, err = db.UpdateInvoice(
   919  		ref, (*SetID)(setID2),
   920  		getUpdateInvoiceAMPSettle(
   921  			setID2, preimage, CircuitKey{HtlcID: 2},
   922  		),
   923  	)
   924  	require.Nil(t, err)
   925  	_, err = db.UpdateInvoice(
   926  		ref, (*SetID)(setID3),
   927  		getUpdateInvoiceAMPSettle(
   928  			setID3, preimage, CircuitKey{HtlcID: 3},
   929  		),
   930  	)
   931  	require.Nil(t, err)
   932  
   933  	// Now that all the invoices have been settled, we'll ensure that the
   934  	// settle index was updated properly by obtaining all the currently
   935  	// settled invoices in the time series. We use a value of 1 here to
   936  	// ensure we get _all_ the invoices back.
   937  	settledInvoices, err := db.InvoicesSettledSince(1)
   938  	require.Nil(t, err)
   939  
   940  	// To get around the settle index quirk, we'll fetch the very first
   941  	// invoice in the HTLC filtered mode and append it to the set of
   942  	// invoices.
   943  	firstInvoice, err := db.LookupInvoice(InvoiceRefBySetIDFiltered(*setID1))
   944  	require.Nil(t, err)
   945  	settledInvoices = append([]Invoice{firstInvoice}, settledInvoices...)
   946  
   947  	// There should be 3 invoices settled, as we created 3 "sub-invoices"
   948  	// above.
   949  	numInvoices := 3
   950  	require.Equal(t, numInvoices, len(settledInvoices))
   951  
   952  	// Each invoice should match the set of invoices we settled above, and
   953  	// the AMPState should be set accordingly.
   954  	for i, settledInvoice := range settledInvoices {
   955  		// Only one HTLC should be projected for this settled index.
   956  		require.Equal(t, 1, len(settledInvoice.Htlcs))
   957  
   958  		// The invoice should show up as settled, and match the settle
   959  		// index increment.
   960  		invSetID := &[32]byte{byte(i + 1)}
   961  		subInvoiceState, ok := settledInvoice.AMPState[*invSetID]
   962  		require.True(t, ok)
   963  
   964  		require.Equal(t, subInvoiceState.State, HtlcStateSettled)
   965  		require.Equal(t, int(subInvoiceState.SettleIndex), i+1)
   966  
   967  		invoiceKey := CircuitKey{HtlcID: uint64(i + 1)}
   968  		_, keyFound := subInvoiceState.InvoiceKeys[invoiceKey]
   969  		require.True(t, keyFound)
   970  	}
   971  
   972  	// If we attempt to look up the invoice by the payment addr, with all
   973  	// the HTLCs, the main invoice should have 3 HTLCs present.
   974  	refWithHtlcs := InvoiceRefByAddr(testInvoice.Terms.PaymentAddr)
   975  	invoiceWithHTLCs, err := db.LookupInvoice(refWithHtlcs)
   976  	require.Nil(t, err)
   977  	require.Equal(t, numInvoices, len(invoiceWithHTLCs.Htlcs))
   978  
   979  	// Finally, delete the invoice. If we query again, then nothing should
   980  	// be found.
   981  	err = db.DeleteInvoice([]InvoiceDeleteRef{
   982  		{
   983  			PayHash:  payHash,
   984  			PayAddr:  &testInvoice.Terms.PaymentAddr,
   985  			AddIndex: testInvoice.AddIndex,
   986  		},
   987  	})
   988  	require.Nil(t, err)
   989  }
   990  
   991  // TestScanInvoices tests that ScanInvoices scans through all stored invoices
   992  // correctly.
   993  func TestScanInvoices(t *testing.T) {
   994  	t.Parallel()
   995  
   996  	db, cleanup, err := MakeTestDB()
   997  	defer cleanup()
   998  	if err != nil {
   999  		t.Fatalf("unable to make test db: %v", err)
  1000  	}
  1001  
  1002  	var invoices map[lntypes.Hash]*Invoice
  1003  	callCount := 0
  1004  	resetCount := 0
  1005  
  1006  	// reset is used to reset/initialize results and is called once
  1007  	// upon calling ScanInvoices and when the underlying transaction is
  1008  	// retried.
  1009  	reset := func() {
  1010  		invoices = make(map[lntypes.Hash]*Invoice)
  1011  		callCount = 0
  1012  		resetCount++
  1013  
  1014  	}
  1015  
  1016  	scanFunc := func(paymentHash lntypes.Hash, invoice *Invoice) error {
  1017  		invoices[paymentHash] = invoice
  1018  		callCount++
  1019  
  1020  		return nil
  1021  	}
  1022  
  1023  	// With an empty DB we expect to not scan any invoices.
  1024  	require.NoError(t, db.ScanInvoices(scanFunc, reset))
  1025  	require.Equal(t, 0, len(invoices))
  1026  	require.Equal(t, 0, callCount)
  1027  	require.Equal(t, 1, resetCount)
  1028  
  1029  	numInvoices := 5
  1030  	testInvoices := make(map[lntypes.Hash]*Invoice)
  1031  
  1032  	// Now populate the DB and check if we can get all invoices with their
  1033  	// payment hashes as expected.
  1034  	for i := 1; i <= numInvoices; i++ {
  1035  		invoice, err := randInvoice(lnwire.MilliAtom(i))
  1036  		require.NoError(t, err)
  1037  
  1038  		paymentHash := invoice.Terms.PaymentPreimage.Hash()
  1039  		testInvoices[paymentHash] = invoice
  1040  
  1041  		_, err = db.AddInvoice(invoice, paymentHash)
  1042  		require.NoError(t, err)
  1043  	}
  1044  
  1045  	resetCount = 0
  1046  	require.NoError(t, db.ScanInvoices(scanFunc, reset))
  1047  	require.Equal(t, numInvoices, callCount)
  1048  	require.Equal(t, testInvoices, invoices)
  1049  	require.Equal(t, 1, resetCount)
  1050  }
  1051  
  1052  // TestDuplicateSettleInvoice tests that if we add a new invoice and settle it
  1053  // twice, then the second time we also receive the invoice that we settled as a
  1054  // return argument.
  1055  func TestDuplicateSettleInvoice(t *testing.T) {
  1056  	t.Parallel()
  1057  
  1058  	db, cleanUp, err := MakeTestDB(OptionClock(testClock))
  1059  	defer cleanUp()
  1060  	if err != nil {
  1061  		t.Fatalf("unable to make test db: %v", err)
  1062  	}
  1063  
  1064  	// We'll start out by creating an invoice and writing it to the DB.
  1065  	amt := lnwire.NewMAtomsFromAtoms(1000)
  1066  	invoice, err := randInvoice(amt)
  1067  	if err != nil {
  1068  		t.Fatalf("unable to create invoice: %v", err)
  1069  	}
  1070  
  1071  	payHash := invoice.Terms.PaymentPreimage.Hash()
  1072  
  1073  	if _, err := db.AddInvoice(invoice, payHash); err != nil {
  1074  		t.Fatalf("unable to add invoice %v", err)
  1075  	}
  1076  
  1077  	// With the invoice in the DB, we'll now attempt to settle the invoice.
  1078  	ref := InvoiceRefByHash(payHash)
  1079  	dbInvoice, err := db.UpdateInvoice(ref, nil, getUpdateInvoice(amt))
  1080  	if err != nil {
  1081  		t.Fatalf("unable to settle invoice: %v", err)
  1082  	}
  1083  
  1084  	// We'll update what we expect the settle invoice to be so that our
  1085  	// comparison below has the correct assumption.
  1086  	invoice.SettleIndex = 1
  1087  	invoice.State = ContractSettled
  1088  	invoice.AmtPaid = amt
  1089  	invoice.SettleDate = dbInvoice.SettleDate
  1090  	invoice.Htlcs = map[CircuitKey]*InvoiceHTLC{
  1091  		{}: {
  1092  			Amt:           amt,
  1093  			AcceptTime:    time.Unix(1, 0),
  1094  			ResolveTime:   time.Unix(1, 0),
  1095  			State:         HtlcStateSettled,
  1096  			CustomRecords: make(record.CustomSet),
  1097  		},
  1098  	}
  1099  
  1100  	// We should get back the exact same invoice that we just inserted.
  1101  	require.Equal(t, invoice, dbInvoice, "wrong invoice after settle")
  1102  
  1103  	// If we try to settle the invoice again, then we should get the very
  1104  	// same invoice back, but with an error this time.
  1105  	dbInvoice, err = db.UpdateInvoice(ref, nil, getUpdateInvoice(amt))
  1106  	if err != ErrInvoiceAlreadySettled {
  1107  		t.Fatalf("expected ErrInvoiceAlreadySettled")
  1108  	}
  1109  
  1110  	if dbInvoice == nil {
  1111  		t.Fatalf("invoice from db is nil after settle!")
  1112  	}
  1113  
  1114  	invoice.SettleDate = dbInvoice.SettleDate
  1115  	require.Equal(t, invoice, dbInvoice, "wrong invoice after second settle")
  1116  }
  1117  
  1118  // TestQueryInvoices ensures that we can properly query the invoice database
  1119  // for invoices using different types of queries.
  1120  func TestQueryInvoices(t *testing.T) {
  1121  	t.Parallel()
  1122  
  1123  	db, cleanUp, err := MakeTestDB(OptionClock(testClock))
  1124  	defer cleanUp()
  1125  	if err != nil {
  1126  		t.Fatalf("unable to make test db: %v", err)
  1127  	}
  1128  
  1129  	// To begin the test, we'll add 50 invoices to the database. We'll
  1130  	// assume that the index of the invoice within the database is the same
  1131  	// as the amount of the invoice itself.
  1132  	const numInvoices = 50
  1133  	var settleIndex uint64 = 1
  1134  	var invoices []Invoice
  1135  	var pendingInvoices []Invoice
  1136  
  1137  	for i := 1; i <= numInvoices; i++ {
  1138  		amt := lnwire.MilliAtom(i)
  1139  		invoice, err := randInvoice(amt)
  1140  		if err != nil {
  1141  			t.Fatalf("unable to create invoice: %v", err)
  1142  		}
  1143  
  1144  		paymentHash := invoice.Terms.PaymentPreimage.Hash()
  1145  
  1146  		if _, err := db.AddInvoice(invoice, paymentHash); err != nil {
  1147  			t.Fatalf("unable to add invoice: %v", err)
  1148  		}
  1149  
  1150  		// We'll only settle half of all invoices created.
  1151  		if i%2 == 0 {
  1152  			ref := InvoiceRefByHash(paymentHash)
  1153  			_, err := db.UpdateInvoice(ref, nil, getUpdateInvoice(amt))
  1154  			if err != nil {
  1155  				t.Fatalf("unable to settle invoice: %v", err)
  1156  			}
  1157  
  1158  			// Create the settled invoice for the expectation set.
  1159  			settleTestInvoice(invoice, settleIndex)
  1160  			settleIndex++
  1161  		} else {
  1162  			pendingInvoices = append(pendingInvoices, *invoice)
  1163  		}
  1164  
  1165  		invoices = append(invoices, *invoice)
  1166  	}
  1167  
  1168  	// The test will consist of several queries along with their respective
  1169  	// expected response. Each query response should match its expected one.
  1170  	testCases := []struct {
  1171  		query    InvoiceQuery
  1172  		expected []Invoice
  1173  	}{
  1174  		// Fetch all invoices with a single query.
  1175  		{
  1176  			query: InvoiceQuery{
  1177  				NumMaxInvoices: numInvoices,
  1178  			},
  1179  			expected: invoices,
  1180  		},
  1181  		// Fetch all invoices with a single query, reversed.
  1182  		{
  1183  			query: InvoiceQuery{
  1184  				Reversed:       true,
  1185  				NumMaxInvoices: numInvoices,
  1186  			},
  1187  			expected: invoices,
  1188  		},
  1189  		// Fetch the first 25 invoices.
  1190  		{
  1191  			query: InvoiceQuery{
  1192  				NumMaxInvoices: numInvoices / 2,
  1193  			},
  1194  			expected: invoices[:numInvoices/2],
  1195  		},
  1196  		// Fetch the first 10 invoices, but this time iterating
  1197  		// backwards.
  1198  		{
  1199  			query: InvoiceQuery{
  1200  				IndexOffset:    11,
  1201  				Reversed:       true,
  1202  				NumMaxInvoices: numInvoices,
  1203  			},
  1204  			expected: invoices[:10],
  1205  		},
  1206  		// Fetch the last 40 invoices.
  1207  		{
  1208  			query: InvoiceQuery{
  1209  				IndexOffset:    10,
  1210  				NumMaxInvoices: numInvoices,
  1211  			},
  1212  			expected: invoices[10:],
  1213  		},
  1214  		// Fetch all but the first invoice.
  1215  		{
  1216  			query: InvoiceQuery{
  1217  				IndexOffset:    1,
  1218  				NumMaxInvoices: numInvoices,
  1219  			},
  1220  			expected: invoices[1:],
  1221  		},
  1222  		// Fetch one invoice, reversed, with index offset 3. This
  1223  		// should give us the second invoice in the array.
  1224  		{
  1225  			query: InvoiceQuery{
  1226  				IndexOffset:    3,
  1227  				Reversed:       true,
  1228  				NumMaxInvoices: 1,
  1229  			},
  1230  			expected: invoices[1:2],
  1231  		},
  1232  		// Same as above, at index 2.
  1233  		{
  1234  			query: InvoiceQuery{
  1235  				IndexOffset:    2,
  1236  				Reversed:       true,
  1237  				NumMaxInvoices: 1,
  1238  			},
  1239  			expected: invoices[0:1],
  1240  		},
  1241  		// Fetch one invoice, at index 1, reversed. Since invoice#1 is
  1242  		// the very first, there won't be any left in a reverse search,
  1243  		// so we expect no invoices to be returned.
  1244  		{
  1245  			query: InvoiceQuery{
  1246  				IndexOffset:    1,
  1247  				Reversed:       true,
  1248  				NumMaxInvoices: 1,
  1249  			},
  1250  			expected: nil,
  1251  		},
  1252  		// Same as above, but don't restrict the number of invoices to
  1253  		// 1.
  1254  		{
  1255  			query: InvoiceQuery{
  1256  				IndexOffset:    1,
  1257  				Reversed:       true,
  1258  				NumMaxInvoices: numInvoices,
  1259  			},
  1260  			expected: nil,
  1261  		},
  1262  		// Fetch one invoice, reversed, with no offset set. We expect
  1263  		// the last invoice in the response.
  1264  		{
  1265  			query: InvoiceQuery{
  1266  				Reversed:       true,
  1267  				NumMaxInvoices: 1,
  1268  			},
  1269  			expected: invoices[numInvoices-1:],
  1270  		},
  1271  		// Fetch one invoice, reversed, the offset set at numInvoices+1.
  1272  		// We expect this to return the last invoice.
  1273  		{
  1274  			query: InvoiceQuery{
  1275  				IndexOffset:    numInvoices + 1,
  1276  				Reversed:       true,
  1277  				NumMaxInvoices: 1,
  1278  			},
  1279  			expected: invoices[numInvoices-1:],
  1280  		},
  1281  		// Same as above, at offset numInvoices.
  1282  		{
  1283  			query: InvoiceQuery{
  1284  				IndexOffset:    numInvoices,
  1285  				Reversed:       true,
  1286  				NumMaxInvoices: 1,
  1287  			},
  1288  			expected: invoices[numInvoices-2 : numInvoices-1],
  1289  		},
  1290  		// Fetch one invoice, at no offset (same as offset 0). We
  1291  		// expect the first invoice only in the response.
  1292  		{
  1293  			query: InvoiceQuery{
  1294  				NumMaxInvoices: 1,
  1295  			},
  1296  			expected: invoices[:1],
  1297  		},
  1298  		// Same as above, at offset 1.
  1299  		{
  1300  			query: InvoiceQuery{
  1301  				IndexOffset:    1,
  1302  				NumMaxInvoices: 1,
  1303  			},
  1304  			expected: invoices[1:2],
  1305  		},
  1306  		// Same as above, at offset 2.
  1307  		{
  1308  			query: InvoiceQuery{
  1309  				IndexOffset:    2,
  1310  				NumMaxInvoices: 1,
  1311  			},
  1312  			expected: invoices[2:3],
  1313  		},
  1314  		// Same as above, at offset numInvoices-1. Expect the last
  1315  		// invoice to be returned.
  1316  		{
  1317  			query: InvoiceQuery{
  1318  				IndexOffset:    numInvoices - 1,
  1319  				NumMaxInvoices: 1,
  1320  			},
  1321  			expected: invoices[numInvoices-1:],
  1322  		},
  1323  		// Same as above, at offset numInvoices. No invoices should be
  1324  		// returned, as there are no invoices after this offset.
  1325  		{
  1326  			query: InvoiceQuery{
  1327  				IndexOffset:    numInvoices,
  1328  				NumMaxInvoices: 1,
  1329  			},
  1330  			expected: nil,
  1331  		},
  1332  		// Fetch all pending invoices with a single query.
  1333  		{
  1334  			query: InvoiceQuery{
  1335  				PendingOnly:    true,
  1336  				NumMaxInvoices: numInvoices,
  1337  			},
  1338  			expected: pendingInvoices,
  1339  		},
  1340  		// Fetch the first 12 pending invoices.
  1341  		{
  1342  			query: InvoiceQuery{
  1343  				PendingOnly:    true,
  1344  				NumMaxInvoices: numInvoices / 4,
  1345  			},
  1346  			expected: pendingInvoices[:len(pendingInvoices)/2],
  1347  		},
  1348  		// Fetch the first 5 pending invoices, but this time iterating
  1349  		// backwards.
  1350  		{
  1351  			query: InvoiceQuery{
  1352  				IndexOffset:    10,
  1353  				PendingOnly:    true,
  1354  				Reversed:       true,
  1355  				NumMaxInvoices: numInvoices,
  1356  			},
  1357  			// Since we seek to the invoice with index 10 and
  1358  			// iterate backwards, there should only be 5 pending
  1359  			// invoices before it as every other invoice within the
  1360  			// index is settled.
  1361  			expected: pendingInvoices[:5],
  1362  		},
  1363  		// Fetch the last 15 invoices.
  1364  		{
  1365  			query: InvoiceQuery{
  1366  				IndexOffset:    20,
  1367  				PendingOnly:    true,
  1368  				NumMaxInvoices: numInvoices,
  1369  			},
  1370  			// Since we seek to the invoice with index 20, there are
  1371  			// 30 invoices left. From these 30, only 15 of them are
  1372  			// still pending.
  1373  			expected: pendingInvoices[len(pendingInvoices)-15:],
  1374  		},
  1375  		// Fetch all invoices paginating backwards, with an index offset
  1376  		// that is beyond our last offset. We expect all invoices to be
  1377  		// returned.
  1378  		{
  1379  			query: InvoiceQuery{
  1380  				IndexOffset:    numInvoices * 2,
  1381  				PendingOnly:    false,
  1382  				Reversed:       true,
  1383  				NumMaxInvoices: numInvoices,
  1384  			},
  1385  			expected: invoices,
  1386  		},
  1387  	}
  1388  
  1389  	for i, testCase := range testCases {
  1390  		response, err := db.QueryInvoices(testCase.query)
  1391  		if err != nil {
  1392  			t.Fatalf("unable to query invoice database: %v", err)
  1393  		}
  1394  
  1395  		require.Equal(t, len(testCase.expected), len(response.Invoices))
  1396  
  1397  		for j, expected := range testCase.expected {
  1398  			require.Equal(t,
  1399  				expected, response.Invoices[j],
  1400  				fmt.Sprintf("test: #%v, item: #%v", i, j),
  1401  			)
  1402  		}
  1403  	}
  1404  }
  1405  
  1406  // getUpdateInvoice returns an invoice update callback that, when called,
  1407  // settles the invoice with the given amount.
  1408  func getUpdateInvoice(amt lnwire.MilliAtom) InvoiceUpdateCallback {
  1409  	return func(invoice *Invoice) (*InvoiceUpdateDesc, error) {
  1410  		if invoice.State == ContractSettled {
  1411  			return nil, ErrInvoiceAlreadySettled
  1412  		}
  1413  
  1414  		noRecords := make(record.CustomSet)
  1415  
  1416  		update := &InvoiceUpdateDesc{
  1417  			State: &InvoiceStateUpdateDesc{
  1418  				Preimage: invoice.Terms.PaymentPreimage,
  1419  				NewState: ContractSettled,
  1420  			},
  1421  			AddHtlcs: map[CircuitKey]*HtlcAcceptDesc{
  1422  				{}: {
  1423  					Amt:           amt,
  1424  					CustomRecords: noRecords,
  1425  				},
  1426  			},
  1427  		}
  1428  
  1429  		return update, nil
  1430  	}
  1431  }
  1432  
  1433  // TestCustomRecords tests that custom records are properly recorded in the
  1434  // invoice database.
  1435  func TestCustomRecords(t *testing.T) {
  1436  	t.Parallel()
  1437  
  1438  	db, cleanUp, err := MakeTestDB()
  1439  	defer cleanUp()
  1440  	if err != nil {
  1441  		t.Fatalf("unable to make test db: %v", err)
  1442  	}
  1443  
  1444  	preimage := lntypes.Preimage{1}
  1445  	paymentHash := preimage.Hash()
  1446  
  1447  	testInvoice := &Invoice{
  1448  		Htlcs: map[CircuitKey]*InvoiceHTLC{},
  1449  		Terms: ContractTerm{
  1450  			Value:           lnwire.NewMAtomsFromAtoms(10000),
  1451  			Features:        emptyFeatures,
  1452  			PaymentPreimage: &preimage,
  1453  		},
  1454  	}
  1455  
  1456  	if _, err := db.AddInvoice(testInvoice, paymentHash); err != nil {
  1457  		t.Fatalf("unable to add invoice: %v", err)
  1458  	}
  1459  
  1460  	// Accept an htlc with custom records on this invoice.
  1461  	key := CircuitKey{ChanID: lnwire.NewShortChanIDFromInt(1), HtlcID: 4}
  1462  
  1463  	records := record.CustomSet{
  1464  		100000: []byte{},
  1465  		100001: []byte{1, 2},
  1466  	}
  1467  
  1468  	ref := InvoiceRefByHash(paymentHash)
  1469  	_, err = db.UpdateInvoice(ref, nil,
  1470  		func(invoice *Invoice) (*InvoiceUpdateDesc, error) {
  1471  			return &InvoiceUpdateDesc{
  1472  				AddHtlcs: map[CircuitKey]*HtlcAcceptDesc{
  1473  					key: {
  1474  						Amt:           500,
  1475  						CustomRecords: records,
  1476  					},
  1477  				},
  1478  			}, nil
  1479  		},
  1480  	)
  1481  	if err != nil {
  1482  		t.Fatalf("unable to add invoice htlc: %v", err)
  1483  	}
  1484  
  1485  	// Retrieve the invoice from that database and verify that the custom
  1486  	// records are present.
  1487  	dbInvoice, err := db.LookupInvoice(ref)
  1488  	if err != nil {
  1489  		t.Fatalf("unable to lookup invoice: %v", err)
  1490  	}
  1491  
  1492  	if len(dbInvoice.Htlcs) != 1 {
  1493  		t.Fatalf("expected the htlc to be added")
  1494  	}
  1495  
  1496  	require.Equal(t,
  1497  		records, dbInvoice.Htlcs[key].CustomRecords,
  1498  		"invalid custom records",
  1499  	)
  1500  }
  1501  
  1502  // TestInvoiceHtlcAMPFields asserts that the set id and preimage fields are
  1503  // properly recorded when updating an invoice.
  1504  func TestInvoiceHtlcAMPFields(t *testing.T) {
  1505  	t.Run("amp", func(t *testing.T) {
  1506  		testInvoiceHtlcAMPFields(t, true)
  1507  	})
  1508  	t.Run("no amp", func(t *testing.T) {
  1509  		testInvoiceHtlcAMPFields(t, false)
  1510  	})
  1511  }
  1512  
  1513  func testInvoiceHtlcAMPFields(t *testing.T, isAMP bool) {
  1514  	db, cleanUp, err := MakeTestDB()
  1515  	defer cleanUp()
  1516  	require.Nil(t, err)
  1517  
  1518  	testInvoice, err := randInvoice(1000)
  1519  	require.Nil(t, err)
  1520  
  1521  	if isAMP {
  1522  		testInvoice.Terms.Features = ampFeatures
  1523  	}
  1524  
  1525  	payHash := testInvoice.Terms.PaymentPreimage.Hash()
  1526  	_, err = db.AddInvoice(testInvoice, payHash)
  1527  	require.Nil(t, err)
  1528  
  1529  	// Accept an htlc with custom records on this invoice.
  1530  	key := CircuitKey{ChanID: lnwire.NewShortChanIDFromInt(1), HtlcID: 4}
  1531  	records := make(map[uint64][]byte)
  1532  
  1533  	var ampData *InvoiceHtlcAMPData
  1534  	if isAMP {
  1535  		amp := record.NewAMP([32]byte{1}, [32]byte{2}, 3)
  1536  		preimage := &lntypes.Preimage{4}
  1537  
  1538  		ampData = &InvoiceHtlcAMPData{
  1539  			Record:   *amp,
  1540  			Hash:     preimage.Hash(),
  1541  			Preimage: preimage,
  1542  		}
  1543  	}
  1544  
  1545  	ref := InvoiceRefByHash(payHash)
  1546  	_, err = db.UpdateInvoice(ref, nil,
  1547  		func(invoice *Invoice) (*InvoiceUpdateDesc, error) {
  1548  			return &InvoiceUpdateDesc{
  1549  				AddHtlcs: map[CircuitKey]*HtlcAcceptDesc{
  1550  					key: {
  1551  						Amt:           500,
  1552  						AMP:           ampData,
  1553  						CustomRecords: records,
  1554  					},
  1555  				},
  1556  			}, nil
  1557  		},
  1558  	)
  1559  	require.Nil(t, err)
  1560  
  1561  	// Retrieve the invoice from that database and verify that the AMP
  1562  	// fields are as expected.
  1563  	dbInvoice, err := db.LookupInvoice(ref)
  1564  	require.Nil(t, err)
  1565  
  1566  	require.Equal(t, 1, len(dbInvoice.Htlcs))
  1567  	require.Equal(t, ampData, dbInvoice.Htlcs[key].AMP)
  1568  }
  1569  
  1570  // TestInvoiceRef asserts that the proper identifiers are returned from an
  1571  // InvoiceRef depending on the constructor used.
  1572  func TestInvoiceRef(t *testing.T) {
  1573  	payHash := lntypes.Hash{0x01}
  1574  	payAddr := [32]byte{0x02}
  1575  	setID := [32]byte{0x03}
  1576  
  1577  	// An InvoiceRef by hash should return the provided hash and a nil
  1578  	// payment addr.
  1579  	refByHash := InvoiceRefByHash(payHash)
  1580  	require.Equal(t, &payHash, refByHash.PayHash())
  1581  	require.Equal(t, (*[32]byte)(nil), refByHash.PayAddr())
  1582  	require.Equal(t, (*[32]byte)(nil), refByHash.SetID())
  1583  
  1584  	// An InvoiceRef by hash and addr should return the payment hash and
  1585  	// payment addr passed to the constructor.
  1586  	refByHashAndAddr := InvoiceRefByHashAndAddr(payHash, payAddr)
  1587  	require.Equal(t, &payHash, refByHashAndAddr.PayHash())
  1588  	require.Equal(t, &payAddr, refByHashAndAddr.PayAddr())
  1589  	require.Equal(t, (*[32]byte)(nil), refByHashAndAddr.SetID())
  1590  
  1591  	// An InvoiceRef by set id should return an empty pay hash, a nil pay
  1592  	// addr, and a reference to the given set id.
  1593  	refBySetID := InvoiceRefBySetID(setID)
  1594  	require.Equal(t, (*lntypes.Hash)(nil), refBySetID.PayHash())
  1595  	require.Equal(t, (*[32]byte)(nil), refBySetID.PayAddr())
  1596  	require.Equal(t, &setID, refBySetID.SetID())
  1597  
  1598  	// An InvoiceRef by pay addr should only return a pay addr, but nil for
  1599  	// pay hash and set id.
  1600  	refByAddr := InvoiceRefByAddr(payAddr)
  1601  	require.Equal(t, (*lntypes.Hash)(nil), refByAddr.PayHash())
  1602  	require.Equal(t, &payAddr, refByAddr.PayAddr())
  1603  	require.Equal(t, (*[32]byte)(nil), refByAddr.SetID())
  1604  }
  1605  
  1606  // TestHTLCSet asserts that HTLCSet returns the proper set of accepted HTLCs
  1607  // that can be considered for settlement. It asserts that MPP and AMP HTLCs do
  1608  // not comingle, and also that HTLCs with disjoint set ids appear in different
  1609  // sets.
  1610  func TestHTLCSet(t *testing.T) {
  1611  	inv := &Invoice{
  1612  		Htlcs: make(map[CircuitKey]*InvoiceHTLC),
  1613  	}
  1614  
  1615  	// Construct two distinct set id's, in this test we'll also track the
  1616  	// nil set id as a third group.
  1617  	setID1 := &[32]byte{1}
  1618  	setID2 := &[32]byte{2}
  1619  
  1620  	// Create the expected htlc sets for each group, these will be updated
  1621  	// as the invoice is modified.
  1622  	expSetNil := make(map[CircuitKey]*InvoiceHTLC)
  1623  	expSet1 := make(map[CircuitKey]*InvoiceHTLC)
  1624  	expSet2 := make(map[CircuitKey]*InvoiceHTLC)
  1625  
  1626  	checkHTLCSets := func() {
  1627  		require.Equal(t, expSetNil, inv.HTLCSet(nil, HtlcStateAccepted))
  1628  		require.Equal(t, expSet1, inv.HTLCSet(setID1, HtlcStateAccepted))
  1629  		require.Equal(t, expSet2, inv.HTLCSet(setID2, HtlcStateAccepted))
  1630  	}
  1631  
  1632  	// All HTLC sets should be empty initially.
  1633  	checkHTLCSets()
  1634  
  1635  	// Add the following sequence of HTLCs to the invoice, sanity checking
  1636  	// all three HTLC sets after each transition. This sequence asserts:
  1637  	//   - both nil and non-nil set ids can have multiple htlcs.
  1638  	//   - there may be distinct htlc sets with non-nil set ids.
  1639  	//   - only accepted htlcs are returned as part of the set.
  1640  	htlcs := []struct {
  1641  		setID *[32]byte
  1642  		state HtlcState
  1643  	}{
  1644  		{nil, HtlcStateAccepted},
  1645  		{nil, HtlcStateAccepted},
  1646  		{setID1, HtlcStateAccepted},
  1647  		{setID1, HtlcStateAccepted},
  1648  		{setID2, HtlcStateAccepted},
  1649  		{setID2, HtlcStateAccepted},
  1650  		{nil, HtlcStateCanceled},
  1651  		{setID1, HtlcStateCanceled},
  1652  		{setID2, HtlcStateCanceled},
  1653  		{nil, HtlcStateSettled},
  1654  		{setID1, HtlcStateSettled},
  1655  		{setID2, HtlcStateSettled},
  1656  	}
  1657  
  1658  	for i, h := range htlcs {
  1659  		var ampData *InvoiceHtlcAMPData
  1660  		if h.setID != nil {
  1661  			ampData = &InvoiceHtlcAMPData{
  1662  				Record: *record.NewAMP([32]byte{0}, *h.setID, 0),
  1663  			}
  1664  
  1665  		}
  1666  
  1667  		// Add the HTLC to the invoice's set of HTLCs.
  1668  		key := CircuitKey{HtlcID: uint64(i)}
  1669  		htlc := &InvoiceHTLC{
  1670  			AMP:   ampData,
  1671  			State: h.state,
  1672  		}
  1673  		inv.Htlcs[key] = htlc
  1674  
  1675  		// Update our expected htlc set if the htlc is accepted,
  1676  		// otherwise it shouldn't be reflected.
  1677  		if h.state == HtlcStateAccepted {
  1678  			switch h.setID {
  1679  			case nil:
  1680  				expSetNil[key] = htlc
  1681  			case setID1:
  1682  				expSet1[key] = htlc
  1683  			case setID2:
  1684  				expSet2[key] = htlc
  1685  			default:
  1686  				t.Fatalf("unexpected set id")
  1687  			}
  1688  		}
  1689  
  1690  		checkHTLCSets()
  1691  	}
  1692  }
  1693  
  1694  // TestAddInvoiceWithHTLCs asserts that you can't insert an invoice that already
  1695  // has HTLCs.
  1696  func TestAddInvoiceWithHTLCs(t *testing.T) {
  1697  	db, cleanUp, err := MakeTestDB()
  1698  	defer cleanUp()
  1699  	require.Nil(t, err)
  1700  
  1701  	testInvoice, err := randInvoice(1000)
  1702  	require.Nil(t, err)
  1703  
  1704  	key := CircuitKey{HtlcID: 1}
  1705  	testInvoice.Htlcs[key] = &InvoiceHTLC{}
  1706  
  1707  	payHash := testInvoice.Terms.PaymentPreimage.Hash()
  1708  	_, err = db.AddInvoice(testInvoice, payHash)
  1709  	require.Equal(t, ErrInvoiceHasHtlcs, err)
  1710  }
  1711  
  1712  // TestSetIDIndex asserts that the set id index properly adds new invoices as we
  1713  // accept HTLCs, that they can be queried by their set id after accepting, and
  1714  // that invoices with duplicate set ids are disallowed.
  1715  func TestSetIDIndex(t *testing.T) {
  1716  	testClock := clock.NewTestClock(testNow)
  1717  	db, cleanUp, err := MakeTestDB(OptionClock(testClock))
  1718  	defer cleanUp()
  1719  	require.Nil(t, err)
  1720  
  1721  	// We'll start out by creating an invoice and writing it to the DB.
  1722  	amt := lnwire.NewMAtomsFromAtoms(1000)
  1723  	invoice, err := randInvoice(amt)
  1724  	require.Nil(t, err)
  1725  
  1726  	// Set AMP-specific features so that we can settle with HTLC-level
  1727  	// preimages.
  1728  	invoice.Terms.Features = ampFeatures
  1729  
  1730  	preimage := *invoice.Terms.PaymentPreimage
  1731  	payHash := preimage.Hash()
  1732  	_, err = db.AddInvoice(invoice, payHash)
  1733  	require.Nil(t, err)
  1734  
  1735  	setID := &[32]byte{1}
  1736  
  1737  	// Update the invoice with an accepted HTLC that also accepts the
  1738  	// invoice.
  1739  	ref := InvoiceRefByHashAndAddr(payHash, invoice.Terms.PaymentAddr)
  1740  	dbInvoice, err := db.UpdateInvoice(
  1741  		ref, (*SetID)(setID), updateAcceptAMPHtlc(0, amt, setID, true),
  1742  	)
  1743  	require.Nil(t, err)
  1744  
  1745  	// We'll update what we expect the accepted invoice to be so that our
  1746  	// comparison below has the correct assumption.
  1747  	invoice.State = ContractOpen
  1748  	invoice.AmtPaid = amt
  1749  	invoice.SettleDate = dbInvoice.SettleDate
  1750  	invoice.Htlcs = map[CircuitKey]*InvoiceHTLC{
  1751  		{HtlcID: 0}: makeAMPInvoiceHTLC(amt, *setID, payHash, &preimage),
  1752  	}
  1753  	invoice.AMPState = map[SetID]InvoiceStateAMP{}
  1754  	invoice.AMPState[*setID] = InvoiceStateAMP{
  1755  		State:   HtlcStateAccepted,
  1756  		AmtPaid: amt,
  1757  		InvoiceKeys: map[CircuitKey]struct{}{
  1758  			{HtlcID: 0}: {},
  1759  		},
  1760  	}
  1761  
  1762  	// We should get back the exact same invoice that we just inserted.
  1763  	require.Equal(t, invoice, dbInvoice)
  1764  
  1765  	// Now lookup the invoice by set id and see that we get the same one.
  1766  	refBySetID := InvoiceRefBySetID(*setID)
  1767  	dbInvoiceBySetID, err := db.LookupInvoice(refBySetID)
  1768  	require.Nil(t, err)
  1769  	require.Equal(t, invoice, &dbInvoiceBySetID)
  1770  
  1771  	// Trying to accept an HTLC to a different invoice, but using the same
  1772  	// set id should fail.
  1773  	invoice2, err := randInvoice(amt)
  1774  	require.Nil(t, err)
  1775  
  1776  	// Set AMP-specific features so that we can settle with HTLC-level
  1777  	// preimages.
  1778  	invoice2.Terms.Features = ampFeatures
  1779  
  1780  	payHash2 := invoice2.Terms.PaymentPreimage.Hash()
  1781  	_, err = db.AddInvoice(invoice2, payHash2)
  1782  	require.Nil(t, err)
  1783  
  1784  	ref2 := InvoiceRefByHashAndAddr(payHash2, invoice2.Terms.PaymentAddr)
  1785  	_, err = db.UpdateInvoice(
  1786  		ref2, (*SetID)(setID), updateAcceptAMPHtlc(0, amt, setID, true),
  1787  	)
  1788  	require.Equal(t, ErrDuplicateSetID{setID: *setID}, err)
  1789  
  1790  	// Now, begin constructing a second htlc set under a different set id.
  1791  	// This set will contain two distinct HTLCs.
  1792  	setID2 := &[32]byte{2}
  1793  
  1794  	_, err = db.UpdateInvoice(
  1795  		ref, (*SetID)(setID2), updateAcceptAMPHtlc(1, amt, setID2, false),
  1796  	)
  1797  	require.Nil(t, err)
  1798  	dbInvoice, err = db.UpdateInvoice(
  1799  		ref, (*SetID)(setID2), updateAcceptAMPHtlc(2, amt, setID2, false),
  1800  	)
  1801  	require.Nil(t, err)
  1802  
  1803  	// We'll update what we expect the settle invoice to be so that our
  1804  	// comparison below has the correct assumption.
  1805  	invoice.State = ContractOpen
  1806  	invoice.AmtPaid += 2 * amt
  1807  	invoice.SettleDate = dbInvoice.SettleDate
  1808  	invoice.Htlcs = map[CircuitKey]*InvoiceHTLC{
  1809  		{HtlcID: 0}: makeAMPInvoiceHTLC(amt, *setID, payHash, &preimage),
  1810  		{HtlcID: 1}: makeAMPInvoiceHTLC(amt, *setID2, payHash, nil),
  1811  		{HtlcID: 2}: makeAMPInvoiceHTLC(amt, *setID2, payHash, nil),
  1812  	}
  1813  	invoice.AMPState[*setID] = InvoiceStateAMP{
  1814  		State:   HtlcStateAccepted,
  1815  		AmtPaid: amt,
  1816  		InvoiceKeys: map[CircuitKey]struct{}{
  1817  			{HtlcID: 0}: {},
  1818  		},
  1819  	}
  1820  	invoice.AMPState[*setID2] = InvoiceStateAMP{
  1821  		State:   HtlcStateAccepted,
  1822  		AmtPaid: amt * 2,
  1823  		InvoiceKeys: map[CircuitKey]struct{}{
  1824  			{HtlcID: 1}: {},
  1825  			{HtlcID: 2}: {},
  1826  		},
  1827  	}
  1828  
  1829  	// Since UpdateInvoice will only return the sub-set of updated HTLcs,
  1830  	// we'll query again to ensure we get the full set of HTLCs returned.
  1831  	freshInvoice, err := db.LookupInvoice(ref)
  1832  	require.Nil(t, err)
  1833  	dbInvoice = &freshInvoice
  1834  
  1835  	// We should get back the exact same invoice that we just inserted.
  1836  	require.Equal(t, invoice, dbInvoice)
  1837  
  1838  	// Now lookup the invoice by second set id and see that we get the same
  1839  	// index, including the htlcs under the first set id.
  1840  	refBySetID = InvoiceRefBySetID(*setID2)
  1841  	dbInvoiceBySetID, err = db.LookupInvoice(refBySetID)
  1842  	require.Nil(t, err)
  1843  	require.Equal(t, invoice, &dbInvoiceBySetID)
  1844  
  1845  	// Now attempt to settle a non-existent HTLC set, this set ID is the
  1846  	// zero setID so it isn't used for anything internally.
  1847  	_, err = db.UpdateInvoice(
  1848  		ref, nil,
  1849  		getUpdateInvoiceAMPSettle(&[32]byte{}, [32]byte{}, CircuitKey{HtlcID: 99}),
  1850  	)
  1851  	require.Equal(t, ErrEmptyHTLCSet, err)
  1852  
  1853  	// Now settle the first htlc set. The existing HTLCs should remain in
  1854  	// the accepted state and shouldn't be canceled, since we permit an
  1855  	// invoice to be settled multiple times.
  1856  	_, err = db.UpdateInvoice(
  1857  		ref, (*SetID)(setID),
  1858  		getUpdateInvoiceAMPSettle(setID, preimage, CircuitKey{HtlcID: 0}),
  1859  	)
  1860  	require.Nil(t, err)
  1861  
  1862  	freshInvoice, err = db.LookupInvoice(ref)
  1863  	require.Nil(t, err)
  1864  	dbInvoice = &freshInvoice
  1865  
  1866  	invoice.State = ContractOpen
  1867  
  1868  	// The amount paid should reflect that we have 3 present HTLCs, each
  1869  	// with an amount of the original invoice.
  1870  	invoice.AmtPaid = amt * 3
  1871  
  1872  	ampState := invoice.AMPState[*setID]
  1873  	ampState.State = HtlcStateSettled
  1874  	ampState.SettleDate = testNow
  1875  	ampState.SettleIndex = 1
  1876  
  1877  	invoice.AMPState[*setID] = ampState
  1878  
  1879  	invoice.Htlcs[CircuitKey{HtlcID: 0}].State = HtlcStateSettled
  1880  	invoice.Htlcs[CircuitKey{HtlcID: 0}].ResolveTime = time.Unix(1, 0)
  1881  
  1882  	require.Equal(t, invoice, dbInvoice)
  1883  
  1884  	// If we try to settle the same set ID again, then we should get an
  1885  	// error, as it's already been settled.
  1886  	_, err = db.UpdateInvoice(
  1887  		ref, (*SetID)(setID),
  1888  		getUpdateInvoiceAMPSettle(setID, preimage, CircuitKey{HtlcID: 0}),
  1889  	)
  1890  	require.Equal(t, ErrEmptyHTLCSet, err)
  1891  
  1892  	// Next, let's attempt to settle the other active set ID for this
  1893  	// invoice. This will allow us to exercise the case where we go to
  1894  	// settle an invoice with a new setID after one has already been fully
  1895  	// settled.
  1896  	_, err = db.UpdateInvoice(
  1897  		ref, (*SetID)(setID2),
  1898  		getUpdateInvoiceAMPSettle(
  1899  			setID2, preimage, CircuitKey{HtlcID: 1}, CircuitKey{HtlcID: 2},
  1900  		),
  1901  	)
  1902  	require.Nil(t, err)
  1903  
  1904  	freshInvoice, err = db.LookupInvoice(ref)
  1905  	require.Nil(t, err)
  1906  	dbInvoice = &freshInvoice
  1907  
  1908  	// Now the rest of the HTLCs should show as fully settled.
  1909  	ampState = invoice.AMPState[*setID2]
  1910  	ampState.State = HtlcStateSettled
  1911  	ampState.SettleDate = testNow
  1912  	ampState.SettleIndex = 2
  1913  
  1914  	invoice.AMPState[*setID2] = ampState
  1915  
  1916  	invoice.Htlcs[CircuitKey{HtlcID: 1}].State = HtlcStateSettled
  1917  	invoice.Htlcs[CircuitKey{HtlcID: 1}].ResolveTime = time.Unix(1, 0)
  1918  	invoice.Htlcs[CircuitKey{HtlcID: 1}].AMP.Preimage = &preimage
  1919  
  1920  	invoice.Htlcs[CircuitKey{HtlcID: 2}].State = HtlcStateSettled
  1921  	invoice.Htlcs[CircuitKey{HtlcID: 2}].ResolveTime = time.Unix(1, 0)
  1922  	invoice.Htlcs[CircuitKey{HtlcID: 2}].AMP.Preimage = &preimage
  1923  
  1924  	require.Equal(t, invoice, dbInvoice)
  1925  
  1926  	// Lastly, querying for an unknown set id should fail.
  1927  	refUnknownSetID := InvoiceRefBySetID([32]byte{})
  1928  	_, err = db.LookupInvoice(refUnknownSetID)
  1929  	require.Equal(t, ErrInvoiceNotFound, err)
  1930  }
  1931  
  1932  func makeAMPInvoiceHTLC(amt lnwire.MilliAtom, setID [32]byte,
  1933  	hash lntypes.Hash, preimage *lntypes.Preimage) *InvoiceHTLC {
  1934  
  1935  	return &InvoiceHTLC{
  1936  		Amt:           amt,
  1937  		AcceptTime:    testNow,
  1938  		ResolveTime:   time.Time{},
  1939  		State:         HtlcStateAccepted,
  1940  		CustomRecords: make(record.CustomSet),
  1941  		AMP: &InvoiceHtlcAMPData{
  1942  			Record:   *record.NewAMP([32]byte{}, setID, 0),
  1943  			Hash:     hash,
  1944  			Preimage: preimage,
  1945  		},
  1946  	}
  1947  }
  1948  
  1949  // updateAcceptAMPHtlc returns an invoice update callback that, when called,
  1950  // settles the invoice with the given amount.
  1951  func updateAcceptAMPHtlc(id uint64, amt lnwire.MilliAtom,
  1952  	setID *[32]byte, accept bool) InvoiceUpdateCallback {
  1953  
  1954  	return func(invoice *Invoice) (*InvoiceUpdateDesc, error) {
  1955  		if invoice.State == ContractSettled {
  1956  			return nil, ErrInvoiceAlreadySettled
  1957  		}
  1958  
  1959  		noRecords := make(record.CustomSet)
  1960  
  1961  		var (
  1962  			state    *InvoiceStateUpdateDesc
  1963  			preimage *lntypes.Preimage
  1964  		)
  1965  		if accept {
  1966  			state = &InvoiceStateUpdateDesc{
  1967  				NewState: ContractAccepted,
  1968  				SetID:    setID,
  1969  			}
  1970  			pre := *invoice.Terms.PaymentPreimage
  1971  			preimage = &pre
  1972  		}
  1973  
  1974  		ampData := &InvoiceHtlcAMPData{
  1975  			Record:   *record.NewAMP([32]byte{}, *setID, 0),
  1976  			Hash:     invoice.Terms.PaymentPreimage.Hash(),
  1977  			Preimage: preimage,
  1978  		}
  1979  		update := &InvoiceUpdateDesc{
  1980  			State: state,
  1981  			AddHtlcs: map[CircuitKey]*HtlcAcceptDesc{
  1982  				{HtlcID: id}: {
  1983  					Amt:           amt,
  1984  					CustomRecords: noRecords,
  1985  					AMP:           ampData,
  1986  				},
  1987  			},
  1988  		}
  1989  
  1990  		return update, nil
  1991  	}
  1992  }
  1993  
  1994  func getUpdateInvoiceAMPSettle(setID *[32]byte,
  1995  	preimage [32]byte, circuitKeys ...CircuitKey) InvoiceUpdateCallback {
  1996  
  1997  	return func(invoice *Invoice) (*InvoiceUpdateDesc, error) {
  1998  		if invoice.State == ContractSettled {
  1999  			return nil, ErrInvoiceAlreadySettled
  2000  		}
  2001  
  2002  		preImageSet := make(map[CircuitKey]lntypes.Preimage)
  2003  		for _, key := range circuitKeys {
  2004  			preImageSet[key] = preimage
  2005  		}
  2006  
  2007  		update := &InvoiceUpdateDesc{
  2008  			State: &InvoiceStateUpdateDesc{
  2009  				Preimage:      nil,
  2010  				NewState:      ContractSettled,
  2011  				SetID:         setID,
  2012  				HTLCPreimages: preImageSet,
  2013  			},
  2014  		}
  2015  
  2016  		return update, nil
  2017  	}
  2018  }
  2019  
  2020  // TestUnexpectedInvoicePreimage asserts that legacy or MPP invoices cannot be
  2021  // settled when referenced by payment address only. Since regular or MPP
  2022  // payments do not store the payment hash explicitly (it is stored in the
  2023  // index), this enforces that they can only be updated using a InvoiceRefByHash
  2024  // or InvoiceRefByHashOrAddr.
  2025  func TestUnexpectedInvoicePreimage(t *testing.T) {
  2026  	t.Parallel()
  2027  
  2028  	db, cleanup, err := MakeTestDB()
  2029  	defer cleanup()
  2030  	require.NoError(t, err, "unable to make test db")
  2031  
  2032  	invoice, err := randInvoice(lnwire.MilliAtom(100))
  2033  	require.NoError(t, err)
  2034  
  2035  	// Add a random invoice indexed by payment hash and payment addr.
  2036  	paymentHash := invoice.Terms.PaymentPreimage.Hash()
  2037  	_, err = db.AddInvoice(invoice, paymentHash)
  2038  	require.NoError(t, err)
  2039  
  2040  	// Attempt to update the invoice by pay addr only. This will fail since,
  2041  	// in order to settle an MPP invoice, the InvoiceRef must present a
  2042  	// payment hash against which to validate the preimage.
  2043  	_, err = db.UpdateInvoice(
  2044  		InvoiceRefByAddr(invoice.Terms.PaymentAddr), nil,
  2045  		getUpdateInvoice(invoice.Terms.Value),
  2046  	)
  2047  
  2048  	//Assert that we get ErrUnexpectedInvoicePreimage.
  2049  	require.Error(t, ErrUnexpectedInvoicePreimage, err)
  2050  }
  2051  
  2052  type updateHTLCPreimageTestCase struct {
  2053  	name               string
  2054  	settleSamePreimage bool
  2055  	expError           error
  2056  }
  2057  
  2058  // TestUpdateHTLCPreimages asserts various properties of setting HTLC-level
  2059  // preimages on invoice state transitions.
  2060  func TestUpdateHTLCPreimages(t *testing.T) {
  2061  	t.Parallel()
  2062  
  2063  	tests := []updateHTLCPreimageTestCase{
  2064  		{
  2065  			name:               "same preimage on settle",
  2066  			settleSamePreimage: true,
  2067  			expError:           nil,
  2068  		},
  2069  		{
  2070  			name:               "diff preimage on settle",
  2071  			settleSamePreimage: false,
  2072  			expError:           ErrHTLCPreimageAlreadyExists,
  2073  		},
  2074  	}
  2075  
  2076  	for _, test := range tests {
  2077  		test := test
  2078  		t.Run(test.name, func(t *testing.T) {
  2079  			testUpdateHTLCPreimages(t, test)
  2080  		})
  2081  	}
  2082  }
  2083  
  2084  func testUpdateHTLCPreimages(t *testing.T, test updateHTLCPreimageTestCase) {
  2085  	db, cleanup, err := MakeTestDB()
  2086  	defer cleanup()
  2087  	require.NoError(t, err, "unable to make test db")
  2088  
  2089  	// We'll start out by creating an invoice and writing it to the DB.
  2090  	amt := lnwire.NewMAtomsFromAtoms(1000)
  2091  	invoice, err := randInvoice(amt)
  2092  	require.Nil(t, err)
  2093  
  2094  	preimage := *invoice.Terms.PaymentPreimage
  2095  	payHash := preimage.Hash()
  2096  
  2097  	// Set AMP-specific features so that we can settle with HTLC-level
  2098  	// preimages.
  2099  	invoice.Terms.Features = ampFeatures
  2100  
  2101  	_, err = db.AddInvoice(invoice, payHash)
  2102  	require.Nil(t, err)
  2103  
  2104  	setID := &[32]byte{1}
  2105  
  2106  	// Update the invoice with an accepted HTLC that also accepts the
  2107  	// invoice.
  2108  	ref := InvoiceRefByAddr(invoice.Terms.PaymentAddr)
  2109  	dbInvoice, err := db.UpdateInvoice(
  2110  		ref, (*SetID)(setID), updateAcceptAMPHtlc(0, amt, setID, true),
  2111  	)
  2112  	require.Nil(t, err)
  2113  
  2114  	htlcPreimages := make(map[CircuitKey]lntypes.Preimage)
  2115  	for key := range dbInvoice.Htlcs {
  2116  		// Set the either the same preimage used to accept above, or a
  2117  		// blank preimage depending on the test case.
  2118  		var pre lntypes.Preimage
  2119  		if test.settleSamePreimage {
  2120  			pre = preimage
  2121  		}
  2122  		htlcPreimages[key] = pre
  2123  	}
  2124  
  2125  	updateInvoice := func(invoice *Invoice) (*InvoiceUpdateDesc, error) {
  2126  		update := &InvoiceUpdateDesc{
  2127  			State: &InvoiceStateUpdateDesc{
  2128  				Preimage:      nil,
  2129  				NewState:      ContractSettled,
  2130  				HTLCPreimages: htlcPreimages,
  2131  				SetID:         setID,
  2132  			},
  2133  		}
  2134  
  2135  		return update, nil
  2136  	}
  2137  
  2138  	// Now settle the HTLC set and assert the resulting error.
  2139  	_, err = db.UpdateInvoice(ref, (*SetID)(setID), updateInvoice)
  2140  	require.Equal(t, test.expError, err)
  2141  }
  2142  
  2143  type updateHTLCTest struct {
  2144  	name     string
  2145  	input    InvoiceHTLC
  2146  	invState ContractState
  2147  	setID    *[32]byte
  2148  	output   InvoiceHTLC
  2149  	expErr   error
  2150  }
  2151  
  2152  // TestUpdateHTLC asserts the behavior of the updateHTLC method in various
  2153  // scenarios for MPP and AMP.
  2154  func TestUpdateHTLC(t *testing.T) {
  2155  	t.Parallel()
  2156  
  2157  	setID := [32]byte{0x01}
  2158  	ampRecord := record.NewAMP([32]byte{0x02}, setID, 3)
  2159  	preimage := lntypes.Preimage{0x04}
  2160  	hash := preimage.Hash()
  2161  
  2162  	diffSetID := [32]byte{0x05}
  2163  	fakePreimage := lntypes.Preimage{0x06}
  2164  	testAlreadyNow := time.Now()
  2165  
  2166  	tests := []updateHTLCTest{
  2167  		{
  2168  			name: "MPP accept",
  2169  			input: InvoiceHTLC{
  2170  				Amt:           5000,
  2171  				MppTotalAmt:   5000,
  2172  				AcceptHeight:  100,
  2173  				AcceptTime:    testNow,
  2174  				ResolveTime:   time.Time{},
  2175  				Expiry:        40,
  2176  				State:         HtlcStateAccepted,
  2177  				CustomRecords: make(record.CustomSet),
  2178  				AMP:           nil,
  2179  			},
  2180  			invState: ContractAccepted,
  2181  			setID:    nil,
  2182  			output: InvoiceHTLC{
  2183  				Amt:           5000,
  2184  				MppTotalAmt:   5000,
  2185  				AcceptHeight:  100,
  2186  				AcceptTime:    testNow,
  2187  				ResolveTime:   time.Time{},
  2188  				Expiry:        40,
  2189  				State:         HtlcStateAccepted,
  2190  				CustomRecords: make(record.CustomSet),
  2191  				AMP:           nil,
  2192  			},
  2193  			expErr: nil,
  2194  		},
  2195  		{
  2196  			name: "MPP settle",
  2197  			input: InvoiceHTLC{
  2198  				Amt:           5000,
  2199  				MppTotalAmt:   5000,
  2200  				AcceptHeight:  100,
  2201  				AcceptTime:    testNow,
  2202  				ResolveTime:   time.Time{},
  2203  				Expiry:        40,
  2204  				State:         HtlcStateAccepted,
  2205  				CustomRecords: make(record.CustomSet),
  2206  				AMP:           nil,
  2207  			},
  2208  			invState: ContractSettled,
  2209  			setID:    nil,
  2210  			output: InvoiceHTLC{
  2211  				Amt:           5000,
  2212  				MppTotalAmt:   5000,
  2213  				AcceptHeight:  100,
  2214  				AcceptTime:    testNow,
  2215  				ResolveTime:   testNow,
  2216  				Expiry:        40,
  2217  				State:         HtlcStateSettled,
  2218  				CustomRecords: make(record.CustomSet),
  2219  				AMP:           nil,
  2220  			},
  2221  			expErr: nil,
  2222  		},
  2223  		{
  2224  			name: "MPP cancel",
  2225  			input: InvoiceHTLC{
  2226  				Amt:           5000,
  2227  				MppTotalAmt:   5000,
  2228  				AcceptHeight:  100,
  2229  				AcceptTime:    testNow,
  2230  				ResolveTime:   time.Time{},
  2231  				Expiry:        40,
  2232  				State:         HtlcStateAccepted,
  2233  				CustomRecords: make(record.CustomSet),
  2234  				AMP:           nil,
  2235  			},
  2236  			invState: ContractCanceled,
  2237  			setID:    nil,
  2238  			output: InvoiceHTLC{
  2239  				Amt:           5000,
  2240  				MppTotalAmt:   5000,
  2241  				AcceptHeight:  100,
  2242  				AcceptTime:    testNow,
  2243  				ResolveTime:   testNow,
  2244  				Expiry:        40,
  2245  				State:         HtlcStateCanceled,
  2246  				CustomRecords: make(record.CustomSet),
  2247  				AMP:           nil,
  2248  			},
  2249  			expErr: nil,
  2250  		},
  2251  		{
  2252  			name: "AMP accept missing preimage",
  2253  			input: InvoiceHTLC{
  2254  				Amt:           5000,
  2255  				MppTotalAmt:   5000,
  2256  				AcceptHeight:  100,
  2257  				AcceptTime:    testNow,
  2258  				ResolveTime:   time.Time{},
  2259  				Expiry:        40,
  2260  				State:         HtlcStateAccepted,
  2261  				CustomRecords: make(record.CustomSet),
  2262  				AMP: &InvoiceHtlcAMPData{
  2263  					Record:   *ampRecord,
  2264  					Hash:     hash,
  2265  					Preimage: nil,
  2266  				},
  2267  			},
  2268  			invState: ContractAccepted,
  2269  			setID:    &setID,
  2270  			output: InvoiceHTLC{
  2271  				Amt:           5000,
  2272  				MppTotalAmt:   5000,
  2273  				AcceptHeight:  100,
  2274  				AcceptTime:    testNow,
  2275  				ResolveTime:   time.Time{},
  2276  				Expiry:        40,
  2277  				State:         HtlcStateAccepted,
  2278  				CustomRecords: make(record.CustomSet),
  2279  				AMP: &InvoiceHtlcAMPData{
  2280  					Record:   *ampRecord,
  2281  					Hash:     hash,
  2282  					Preimage: nil,
  2283  				},
  2284  			},
  2285  			expErr: ErrHTLCPreimageMissing,
  2286  		},
  2287  		{
  2288  			name: "AMP accept invalid preimage",
  2289  			input: InvoiceHTLC{
  2290  				Amt:           5000,
  2291  				MppTotalAmt:   5000,
  2292  				AcceptHeight:  100,
  2293  				AcceptTime:    testNow,
  2294  				ResolveTime:   time.Time{},
  2295  				Expiry:        40,
  2296  				State:         HtlcStateAccepted,
  2297  				CustomRecords: make(record.CustomSet),
  2298  				AMP: &InvoiceHtlcAMPData{
  2299  					Record:   *ampRecord,
  2300  					Hash:     hash,
  2301  					Preimage: &fakePreimage,
  2302  				},
  2303  			},
  2304  			invState: ContractAccepted,
  2305  			setID:    &setID,
  2306  			output: InvoiceHTLC{
  2307  				Amt:           5000,
  2308  				MppTotalAmt:   5000,
  2309  				AcceptHeight:  100,
  2310  				AcceptTime:    testNow,
  2311  				ResolveTime:   time.Time{},
  2312  				Expiry:        40,
  2313  				State:         HtlcStateAccepted,
  2314  				CustomRecords: make(record.CustomSet),
  2315  				AMP: &InvoiceHtlcAMPData{
  2316  					Record:   *ampRecord,
  2317  					Hash:     hash,
  2318  					Preimage: &fakePreimage,
  2319  				},
  2320  			},
  2321  			expErr: ErrHTLCPreimageMismatch,
  2322  		},
  2323  		{
  2324  			name: "AMP accept valid preimage",
  2325  			input: InvoiceHTLC{
  2326  				Amt:           5000,
  2327  				MppTotalAmt:   5000,
  2328  				AcceptHeight:  100,
  2329  				AcceptTime:    testNow,
  2330  				ResolveTime:   time.Time{},
  2331  				Expiry:        40,
  2332  				State:         HtlcStateAccepted,
  2333  				CustomRecords: make(record.CustomSet),
  2334  				AMP: &InvoiceHtlcAMPData{
  2335  					Record:   *ampRecord,
  2336  					Hash:     hash,
  2337  					Preimage: &preimage,
  2338  				},
  2339  			},
  2340  			invState: ContractAccepted,
  2341  			setID:    &setID,
  2342  			output: InvoiceHTLC{
  2343  				Amt:           5000,
  2344  				MppTotalAmt:   5000,
  2345  				AcceptHeight:  100,
  2346  				AcceptTime:    testNow,
  2347  				ResolveTime:   time.Time{},
  2348  				Expiry:        40,
  2349  				State:         HtlcStateAccepted,
  2350  				CustomRecords: make(record.CustomSet),
  2351  				AMP: &InvoiceHtlcAMPData{
  2352  					Record:   *ampRecord,
  2353  					Hash:     hash,
  2354  					Preimage: &preimage,
  2355  				},
  2356  			},
  2357  			expErr: nil,
  2358  		},
  2359  		{
  2360  			name: "AMP accept valid preimage different htlc set",
  2361  			input: InvoiceHTLC{
  2362  				Amt:           5000,
  2363  				MppTotalAmt:   5000,
  2364  				AcceptHeight:  100,
  2365  				AcceptTime:    testNow,
  2366  				ResolveTime:   time.Time{},
  2367  				Expiry:        40,
  2368  				State:         HtlcStateAccepted,
  2369  				CustomRecords: make(record.CustomSet),
  2370  				AMP: &InvoiceHtlcAMPData{
  2371  					Record:   *ampRecord,
  2372  					Hash:     hash,
  2373  					Preimage: &preimage,
  2374  				},
  2375  			},
  2376  			invState: ContractAccepted,
  2377  			setID:    &diffSetID,
  2378  			output: InvoiceHTLC{
  2379  				Amt:           5000,
  2380  				MppTotalAmt:   5000,
  2381  				AcceptHeight:  100,
  2382  				AcceptTime:    testNow,
  2383  				ResolveTime:   time.Time{},
  2384  				Expiry:        40,
  2385  				State:         HtlcStateAccepted,
  2386  				CustomRecords: make(record.CustomSet),
  2387  				AMP: &InvoiceHtlcAMPData{
  2388  					Record:   *ampRecord,
  2389  					Hash:     hash,
  2390  					Preimage: &preimage,
  2391  				},
  2392  			},
  2393  			expErr: nil,
  2394  		},
  2395  		{
  2396  			name: "AMP settle missing preimage",
  2397  			input: InvoiceHTLC{
  2398  				Amt:           5000,
  2399  				MppTotalAmt:   5000,
  2400  				AcceptHeight:  100,
  2401  				AcceptTime:    testNow,
  2402  				ResolveTime:   time.Time{},
  2403  				Expiry:        40,
  2404  				State:         HtlcStateAccepted,
  2405  				CustomRecords: make(record.CustomSet),
  2406  				AMP: &InvoiceHtlcAMPData{
  2407  					Record:   *ampRecord,
  2408  					Hash:     hash,
  2409  					Preimage: nil,
  2410  				},
  2411  			},
  2412  			invState: ContractSettled,
  2413  			setID:    &setID,
  2414  			output: InvoiceHTLC{
  2415  				Amt:           5000,
  2416  				MppTotalAmt:   5000,
  2417  				AcceptHeight:  100,
  2418  				AcceptTime:    testNow,
  2419  				ResolveTime:   time.Time{},
  2420  				Expiry:        40,
  2421  				State:         HtlcStateAccepted,
  2422  				CustomRecords: make(record.CustomSet),
  2423  				AMP: &InvoiceHtlcAMPData{
  2424  					Record:   *ampRecord,
  2425  					Hash:     hash,
  2426  					Preimage: nil,
  2427  				},
  2428  			},
  2429  			expErr: ErrHTLCPreimageMissing,
  2430  		},
  2431  		{
  2432  			name: "AMP settle invalid preimage",
  2433  			input: InvoiceHTLC{
  2434  				Amt:           5000,
  2435  				MppTotalAmt:   5000,
  2436  				AcceptHeight:  100,
  2437  				AcceptTime:    testNow,
  2438  				ResolveTime:   time.Time{},
  2439  				Expiry:        40,
  2440  				State:         HtlcStateAccepted,
  2441  				CustomRecords: make(record.CustomSet),
  2442  				AMP: &InvoiceHtlcAMPData{
  2443  					Record:   *ampRecord,
  2444  					Hash:     hash,
  2445  					Preimage: &fakePreimage,
  2446  				},
  2447  			},
  2448  			invState: ContractSettled,
  2449  			setID:    &setID,
  2450  			output: InvoiceHTLC{
  2451  				Amt:           5000,
  2452  				MppTotalAmt:   5000,
  2453  				AcceptHeight:  100,
  2454  				AcceptTime:    testNow,
  2455  				ResolveTime:   time.Time{},
  2456  				Expiry:        40,
  2457  				State:         HtlcStateAccepted,
  2458  				CustomRecords: make(record.CustomSet),
  2459  				AMP: &InvoiceHtlcAMPData{
  2460  					Record:   *ampRecord,
  2461  					Hash:     hash,
  2462  					Preimage: &fakePreimage,
  2463  				},
  2464  			},
  2465  			expErr: ErrHTLCPreimageMismatch,
  2466  		},
  2467  		{
  2468  			name: "AMP settle valid preimage",
  2469  			input: InvoiceHTLC{
  2470  				Amt:           5000,
  2471  				MppTotalAmt:   5000,
  2472  				AcceptHeight:  100,
  2473  				AcceptTime:    testNow,
  2474  				ResolveTime:   time.Time{},
  2475  				Expiry:        40,
  2476  				State:         HtlcStateAccepted,
  2477  				CustomRecords: make(record.CustomSet),
  2478  				AMP: &InvoiceHtlcAMPData{
  2479  					Record:   *ampRecord,
  2480  					Hash:     hash,
  2481  					Preimage: &preimage,
  2482  				},
  2483  			},
  2484  			invState: ContractSettled,
  2485  			setID:    &setID,
  2486  			output: InvoiceHTLC{
  2487  				Amt:           5000,
  2488  				MppTotalAmt:   5000,
  2489  				AcceptHeight:  100,
  2490  				AcceptTime:    testNow,
  2491  				ResolveTime:   testNow,
  2492  				Expiry:        40,
  2493  				State:         HtlcStateSettled,
  2494  				CustomRecords: make(record.CustomSet),
  2495  				AMP: &InvoiceHtlcAMPData{
  2496  					Record:   *ampRecord,
  2497  					Hash:     hash,
  2498  					Preimage: &preimage,
  2499  				},
  2500  			},
  2501  			expErr: nil,
  2502  		},
  2503  		{
  2504  			// With the newer AMP logic, this is now valid, as we
  2505  			// want to be able to accept multiple settle attempts
  2506  			// to a given pay_addr. In this case, the HTLC should
  2507  			// remain in the accepted state.
  2508  			name: "AMP settle valid preimage different htlc set",
  2509  			input: InvoiceHTLC{
  2510  				Amt:           5000,
  2511  				MppTotalAmt:   5000,
  2512  				AcceptHeight:  100,
  2513  				AcceptTime:    testNow,
  2514  				ResolveTime:   time.Time{},
  2515  				Expiry:        40,
  2516  				State:         HtlcStateAccepted,
  2517  				CustomRecords: make(record.CustomSet),
  2518  				AMP: &InvoiceHtlcAMPData{
  2519  					Record:   *ampRecord,
  2520  					Hash:     hash,
  2521  					Preimage: &preimage,
  2522  				},
  2523  			},
  2524  			invState: ContractSettled,
  2525  			setID:    &diffSetID,
  2526  			output: InvoiceHTLC{
  2527  				Amt:           5000,
  2528  				MppTotalAmt:   5000,
  2529  				AcceptHeight:  100,
  2530  				AcceptTime:    testNow,
  2531  				ResolveTime:   time.Time{},
  2532  				Expiry:        40,
  2533  				State:         HtlcStateAccepted,
  2534  				CustomRecords: make(record.CustomSet),
  2535  				AMP: &InvoiceHtlcAMPData{
  2536  					Record:   *ampRecord,
  2537  					Hash:     hash,
  2538  					Preimage: &preimage,
  2539  				},
  2540  			},
  2541  			expErr: nil,
  2542  		},
  2543  		{
  2544  			name: "accept invoice htlc already settled",
  2545  			input: InvoiceHTLC{
  2546  				Amt:           5000,
  2547  				MppTotalAmt:   5000,
  2548  				AcceptHeight:  100,
  2549  				AcceptTime:    testNow,
  2550  				ResolveTime:   testAlreadyNow,
  2551  				Expiry:        40,
  2552  				State:         HtlcStateSettled,
  2553  				CustomRecords: make(record.CustomSet),
  2554  				AMP: &InvoiceHtlcAMPData{
  2555  					Record:   *ampRecord,
  2556  					Hash:     hash,
  2557  					Preimage: &preimage,
  2558  				},
  2559  			},
  2560  			invState: ContractAccepted,
  2561  			setID:    &setID,
  2562  			output: InvoiceHTLC{
  2563  				Amt:           5000,
  2564  				MppTotalAmt:   5000,
  2565  				AcceptHeight:  100,
  2566  				AcceptTime:    testNow,
  2567  				ResolveTime:   testAlreadyNow,
  2568  				Expiry:        40,
  2569  				State:         HtlcStateSettled,
  2570  				CustomRecords: make(record.CustomSet),
  2571  				AMP: &InvoiceHtlcAMPData{
  2572  					Record:   *ampRecord,
  2573  					Hash:     hash,
  2574  					Preimage: &preimage,
  2575  				},
  2576  			},
  2577  			expErr: ErrHTLCAlreadySettled,
  2578  		},
  2579  		{
  2580  			name: "cancel invoice htlc already settled",
  2581  			input: InvoiceHTLC{
  2582  				Amt:           5000,
  2583  				MppTotalAmt:   5000,
  2584  				AcceptHeight:  100,
  2585  				AcceptTime:    testNow,
  2586  				ResolveTime:   testAlreadyNow,
  2587  				Expiry:        40,
  2588  				State:         HtlcStateSettled,
  2589  				CustomRecords: make(record.CustomSet),
  2590  				AMP: &InvoiceHtlcAMPData{
  2591  					Record:   *ampRecord,
  2592  					Hash:     hash,
  2593  					Preimage: &preimage,
  2594  				},
  2595  			},
  2596  			invState: ContractCanceled,
  2597  			setID:    &setID,
  2598  			output: InvoiceHTLC{
  2599  				Amt:           5000,
  2600  				MppTotalAmt:   5000,
  2601  				AcceptHeight:  100,
  2602  				AcceptTime:    testNow,
  2603  				ResolveTime:   testAlreadyNow,
  2604  				Expiry:        40,
  2605  				State:         HtlcStateSettled,
  2606  				CustomRecords: make(record.CustomSet),
  2607  				AMP: &InvoiceHtlcAMPData{
  2608  					Record:   *ampRecord,
  2609  					Hash:     hash,
  2610  					Preimage: &preimage,
  2611  				},
  2612  			},
  2613  			expErr: ErrHTLCAlreadySettled,
  2614  		},
  2615  		{
  2616  			name: "settle invoice htlc already settled",
  2617  			input: InvoiceHTLC{
  2618  				Amt:           5000,
  2619  				MppTotalAmt:   5000,
  2620  				AcceptHeight:  100,
  2621  				AcceptTime:    testNow,
  2622  				ResolveTime:   testAlreadyNow,
  2623  				Expiry:        40,
  2624  				State:         HtlcStateSettled,
  2625  				CustomRecords: make(record.CustomSet),
  2626  				AMP: &InvoiceHtlcAMPData{
  2627  					Record:   *ampRecord,
  2628  					Hash:     hash,
  2629  					Preimage: &preimage,
  2630  				},
  2631  			},
  2632  			invState: ContractSettled,
  2633  			setID:    &setID,
  2634  			output: InvoiceHTLC{
  2635  				Amt:           5000,
  2636  				MppTotalAmt:   5000,
  2637  				AcceptHeight:  100,
  2638  				AcceptTime:    testNow,
  2639  				ResolveTime:   testAlreadyNow,
  2640  				Expiry:        40,
  2641  				State:         HtlcStateSettled,
  2642  				CustomRecords: make(record.CustomSet),
  2643  				AMP: &InvoiceHtlcAMPData{
  2644  					Record:   *ampRecord,
  2645  					Hash:     hash,
  2646  					Preimage: &preimage,
  2647  				},
  2648  			},
  2649  			expErr: nil,
  2650  		},
  2651  		{
  2652  			name: "cancel invoice",
  2653  			input: InvoiceHTLC{
  2654  				Amt:           5000,
  2655  				MppTotalAmt:   5000,
  2656  				AcceptHeight:  100,
  2657  				AcceptTime:    testNow,
  2658  				ResolveTime:   time.Time{},
  2659  				Expiry:        40,
  2660  				State:         HtlcStateAccepted,
  2661  				CustomRecords: make(record.CustomSet),
  2662  				AMP: &InvoiceHtlcAMPData{
  2663  					Record:   *ampRecord,
  2664  					Hash:     hash,
  2665  					Preimage: &preimage,
  2666  				},
  2667  			},
  2668  			invState: ContractCanceled,
  2669  			setID:    &setID,
  2670  			output: InvoiceHTLC{
  2671  				Amt:           5000,
  2672  				MppTotalAmt:   5000,
  2673  				AcceptHeight:  100,
  2674  				AcceptTime:    testNow,
  2675  				ResolveTime:   testNow,
  2676  				Expiry:        40,
  2677  				State:         HtlcStateCanceled,
  2678  				CustomRecords: make(record.CustomSet),
  2679  				AMP: &InvoiceHtlcAMPData{
  2680  					Record:   *ampRecord,
  2681  					Hash:     hash,
  2682  					Preimage: &preimage,
  2683  				},
  2684  			},
  2685  			expErr: nil,
  2686  		},
  2687  		{
  2688  			name: "accept invoice htlc already canceled",
  2689  			input: InvoiceHTLC{
  2690  				Amt:           5000,
  2691  				MppTotalAmt:   5000,
  2692  				AcceptHeight:  100,
  2693  				AcceptTime:    testNow,
  2694  				ResolveTime:   testAlreadyNow,
  2695  				Expiry:        40,
  2696  				State:         HtlcStateCanceled,
  2697  				CustomRecords: make(record.CustomSet),
  2698  				AMP: &InvoiceHtlcAMPData{
  2699  					Record:   *ampRecord,
  2700  					Hash:     hash,
  2701  					Preimage: &preimage,
  2702  				},
  2703  			},
  2704  			invState: ContractAccepted,
  2705  			setID:    &setID,
  2706  			output: InvoiceHTLC{
  2707  				Amt:           5000,
  2708  				MppTotalAmt:   5000,
  2709  				AcceptHeight:  100,
  2710  				AcceptTime:    testNow,
  2711  				ResolveTime:   testAlreadyNow,
  2712  				Expiry:        40,
  2713  				State:         HtlcStateCanceled,
  2714  				CustomRecords: make(record.CustomSet),
  2715  				AMP: &InvoiceHtlcAMPData{
  2716  					Record:   *ampRecord,
  2717  					Hash:     hash,
  2718  					Preimage: &preimage,
  2719  				},
  2720  			},
  2721  			expErr: nil,
  2722  		},
  2723  		{
  2724  			name: "cancel invoice htlc already canceled",
  2725  			input: InvoiceHTLC{
  2726  				Amt:           5000,
  2727  				MppTotalAmt:   5000,
  2728  				AcceptHeight:  100,
  2729  				AcceptTime:    testNow,
  2730  				ResolveTime:   testAlreadyNow,
  2731  				Expiry:        40,
  2732  				State:         HtlcStateCanceled,
  2733  				CustomRecords: make(record.CustomSet),
  2734  				AMP: &InvoiceHtlcAMPData{
  2735  					Record:   *ampRecord,
  2736  					Hash:     hash,
  2737  					Preimage: &preimage,
  2738  				},
  2739  			},
  2740  			invState: ContractCanceled,
  2741  			setID:    &setID,
  2742  			output: InvoiceHTLC{
  2743  				Amt:           5000,
  2744  				MppTotalAmt:   5000,
  2745  				AcceptHeight:  100,
  2746  				AcceptTime:    testNow,
  2747  				ResolveTime:   testAlreadyNow,
  2748  				Expiry:        40,
  2749  				State:         HtlcStateCanceled,
  2750  				CustomRecords: make(record.CustomSet),
  2751  				AMP: &InvoiceHtlcAMPData{
  2752  					Record:   *ampRecord,
  2753  					Hash:     hash,
  2754  					Preimage: &preimage,
  2755  				},
  2756  			},
  2757  			expErr: nil,
  2758  		},
  2759  		{
  2760  			name: "settle invoice htlc already canceled",
  2761  			input: InvoiceHTLC{
  2762  				Amt:           5000,
  2763  				MppTotalAmt:   5000,
  2764  				AcceptHeight:  100,
  2765  				AcceptTime:    testNow,
  2766  				ResolveTime:   testAlreadyNow,
  2767  				Expiry:        40,
  2768  				State:         HtlcStateCanceled,
  2769  				CustomRecords: make(record.CustomSet),
  2770  				AMP: &InvoiceHtlcAMPData{
  2771  					Record:   *ampRecord,
  2772  					Hash:     hash,
  2773  					Preimage: &preimage,
  2774  				},
  2775  			},
  2776  			invState: ContractSettled,
  2777  			setID:    &setID,
  2778  			output: InvoiceHTLC{
  2779  				Amt:           5000,
  2780  				MppTotalAmt:   5000,
  2781  				AcceptHeight:  100,
  2782  				AcceptTime:    testNow,
  2783  				ResolveTime:   testAlreadyNow,
  2784  				Expiry:        40,
  2785  				State:         HtlcStateCanceled,
  2786  				CustomRecords: make(record.CustomSet),
  2787  				AMP: &InvoiceHtlcAMPData{
  2788  					Record:   *ampRecord,
  2789  					Hash:     hash,
  2790  					Preimage: &preimage,
  2791  				},
  2792  			},
  2793  			expErr: nil,
  2794  		},
  2795  	}
  2796  
  2797  	for _, test := range tests {
  2798  		test := test
  2799  		t.Run(test.name, func(t *testing.T) {
  2800  			testUpdateHTLC(t, test)
  2801  		})
  2802  	}
  2803  }
  2804  
  2805  func testUpdateHTLC(t *testing.T, test updateHTLCTest) {
  2806  	htlc := test.input.Copy()
  2807  	_, err := updateHtlc(testNow, htlc, test.invState, test.setID)
  2808  	require.Equal(t, test.expErr, err)
  2809  	require.Equal(t, test.output, *htlc)
  2810  }
  2811  
  2812  // TestDeleteInvoices tests that deleting a list of invoices will succeed
  2813  // if all delete references are valid, or will fail otherwise.
  2814  func TestDeleteInvoices(t *testing.T) {
  2815  	t.Parallel()
  2816  
  2817  	db, cleanup, err := MakeTestDB()
  2818  	defer cleanup()
  2819  	require.NoError(t, err, "unable to make test db")
  2820  
  2821  	// Add some invoices to the test db.
  2822  	numInvoices := 3
  2823  	invoicesToDelete := make([]InvoiceDeleteRef, numInvoices)
  2824  
  2825  	for i := 0; i < numInvoices; i++ {
  2826  		invoice, err := randInvoice(lnwire.MilliAtom(i + 1))
  2827  		require.NoError(t, err)
  2828  
  2829  		paymentHash := invoice.Terms.PaymentPreimage.Hash()
  2830  		addIndex, err := db.AddInvoice(invoice, paymentHash)
  2831  		require.NoError(t, err)
  2832  
  2833  		// Settle the second invoice.
  2834  		if i == 1 {
  2835  			invoice, err = db.UpdateInvoice(
  2836  				InvoiceRefByHash(paymentHash), nil,
  2837  				getUpdateInvoice(invoice.Terms.Value),
  2838  			)
  2839  			require.NoError(t, err, "unable to settle invoice")
  2840  		}
  2841  
  2842  		// store the delete ref for later.
  2843  		invoicesToDelete[i] = InvoiceDeleteRef{
  2844  			PayHash:     paymentHash,
  2845  			PayAddr:     &invoice.Terms.PaymentAddr,
  2846  			AddIndex:    addIndex,
  2847  			SettleIndex: invoice.SettleIndex,
  2848  		}
  2849  	}
  2850  
  2851  	// assertInvoiceCount asserts that the number of invoices equals
  2852  	// to the passed count.
  2853  	assertInvoiceCount := func(count int) {
  2854  		// Query to collect all invoices.
  2855  		query := InvoiceQuery{
  2856  			IndexOffset:    0,
  2857  			NumMaxInvoices: math.MaxUint64,
  2858  		}
  2859  
  2860  		// Check that we really have 3 invoices.
  2861  		response, err := db.QueryInvoices(query)
  2862  		require.NoError(t, err)
  2863  		require.Equal(t, count, len(response.Invoices))
  2864  	}
  2865  
  2866  	// XOR one byte of one of the references' hash and attempt to delete.
  2867  	invoicesToDelete[0].PayHash[2] ^= 3
  2868  	require.Error(t, db.DeleteInvoice(invoicesToDelete))
  2869  	assertInvoiceCount(3)
  2870  
  2871  	// Restore the hash.
  2872  	invoicesToDelete[0].PayHash[2] ^= 3
  2873  
  2874  	// XOR the second invoice's payment settle index as it is settled, and
  2875  	// attempt to delete.
  2876  	invoicesToDelete[1].SettleIndex ^= 11
  2877  	require.Error(t, db.DeleteInvoice(invoicesToDelete))
  2878  	assertInvoiceCount(3)
  2879  
  2880  	// Restore the settle index.
  2881  	invoicesToDelete[1].SettleIndex ^= 11
  2882  
  2883  	// XOR the add index for one of the references and attempt to delete.
  2884  	invoicesToDelete[2].AddIndex ^= 13
  2885  	require.Error(t, db.DeleteInvoice(invoicesToDelete))
  2886  	assertInvoiceCount(3)
  2887  
  2888  	// Restore the add index.
  2889  	invoicesToDelete[2].AddIndex ^= 13
  2890  
  2891  	// Delete should succeed with all the valid references.
  2892  	require.NoError(t, db.DeleteInvoice(invoicesToDelete))
  2893  	assertInvoiceCount(0)
  2894  }
  2895  
  2896  // TestAddInvoiceInvalidFeatureDeps asserts that inserting an invoice with
  2897  // invalid transitive feature dependencies fails with the appropriate error.
  2898  func TestAddInvoiceInvalidFeatureDeps(t *testing.T) {
  2899  	t.Parallel()
  2900  
  2901  	db, cleanup, err := MakeTestDB()
  2902  	require.NoError(t, err, "unable to make test db")
  2903  	defer cleanup()
  2904  
  2905  	invoice, err := randInvoice(500)
  2906  	require.NoError(t, err)
  2907  
  2908  	invoice.Terms.Features = lnwire.NewFeatureVector(
  2909  		lnwire.NewRawFeatureVector(
  2910  			lnwire.TLVOnionPayloadOptional,
  2911  			lnwire.MPPOptional,
  2912  		),
  2913  		lnwire.Features,
  2914  	)
  2915  
  2916  	hash := invoice.Terms.PaymentPreimage.Hash()
  2917  	_, err = db.AddInvoice(invoice, hash)
  2918  	require.Error(t, err, feature.NewErrMissingFeatureDep(
  2919  		lnwire.PaymentAddrOptional,
  2920  	))
  2921  }
  2922  
  2923  // TestEncodeDecodeAmpInvoiceState asserts that the nested TLV
  2924  // encoding+decoding for the AMPInvoiceState struct works as expected.
  2925  func TestEncodeDecodeAmpInvoiceState(t *testing.T) {
  2926  	t.Parallel()
  2927  
  2928  	setID1 := [32]byte{1}
  2929  	setID2 := [32]byte{2}
  2930  	setID3 := [32]byte{3}
  2931  
  2932  	circuitKey1 := CircuitKey{
  2933  		ChanID: lnwire.NewShortChanIDFromInt(1), HtlcID: 1,
  2934  	}
  2935  	circuitKey2 := CircuitKey{
  2936  		ChanID: lnwire.NewShortChanIDFromInt(2), HtlcID: 2,
  2937  	}
  2938  	circuitKey3 := CircuitKey{
  2939  		ChanID: lnwire.NewShortChanIDFromInt(2), HtlcID: 3,
  2940  	}
  2941  
  2942  	// Make a sample invoice state map that we'll encode then decode to
  2943  	// assert equality of.
  2944  	ampState := AMPInvoiceState{
  2945  		setID1: InvoiceStateAMP{
  2946  			State:       HtlcStateSettled,
  2947  			SettleDate:  testNow,
  2948  			SettleIndex: 1,
  2949  			InvoiceKeys: map[CircuitKey]struct{}{
  2950  				circuitKey1: {},
  2951  				circuitKey2: {},
  2952  			},
  2953  			AmtPaid: 5,
  2954  		},
  2955  		setID2: InvoiceStateAMP{
  2956  			State:       HtlcStateCanceled,
  2957  			SettleDate:  testNow,
  2958  			SettleIndex: 2,
  2959  			InvoiceKeys: map[CircuitKey]struct{}{
  2960  				circuitKey1: {},
  2961  			},
  2962  			AmtPaid: 6,
  2963  		},
  2964  		setID3: InvoiceStateAMP{
  2965  			State:       HtlcStateAccepted,
  2966  			SettleDate:  testNow,
  2967  			SettleIndex: 3,
  2968  			InvoiceKeys: map[CircuitKey]struct{}{
  2969  				circuitKey1: {},
  2970  				circuitKey2: {},
  2971  				circuitKey3: {},
  2972  			},
  2973  			AmtPaid: 7,
  2974  		},
  2975  	}
  2976  
  2977  	// We'll now make a sample invoice stream, and use that to encode the
  2978  	// amp state we created above.
  2979  	tlvStream, err := tlv.NewStream(
  2980  		tlv.MakeDynamicRecord(
  2981  			invoiceAmpStateType, &ampState, ampState.recordSize,
  2982  			ampStateEncoder, ampStateDecoder,
  2983  		),
  2984  	)
  2985  	require.Nil(t, err)
  2986  
  2987  	// Next encode the stream into a set of raw bytes.
  2988  	var b bytes.Buffer
  2989  	err = tlvStream.Encode(&b)
  2990  	require.Nil(t, err)
  2991  
  2992  	// Now create a new blank ampState map, which we'll use to decode the
  2993  	// bytes into.
  2994  	ampState2 := make(AMPInvoiceState)
  2995  
  2996  	// Decode from the raw stream into this blank mpa.
  2997  	tlvStream, err = tlv.NewStream(
  2998  		tlv.MakeDynamicRecord(
  2999  			invoiceAmpStateType, &ampState2, nil,
  3000  			ampStateEncoder, ampStateDecoder,
  3001  		),
  3002  	)
  3003  	require.Nil(t, err)
  3004  
  3005  	err = tlvStream.Decode(&b)
  3006  	require.Nil(t, err)
  3007  
  3008  	// The two states should match.
  3009  	require.Equal(t, ampState, ampState2)
  3010  }