github.com/decred/dcrlnd@v0.7.6/invoices/invoiceregistry_test.go (about)

     1  package invoices
     2  
     3  import (
     4  	"crypto/rand"
     5  	"math"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/decred/dcrlnd/amp"
    10  	"github.com/decred/dcrlnd/chainntnfs"
    11  	"github.com/decred/dcrlnd/channeldb"
    12  	"github.com/decred/dcrlnd/clock"
    13  	"github.com/decred/dcrlnd/lntypes"
    14  	"github.com/decred/dcrlnd/lnwire"
    15  	"github.com/decred/dcrlnd/record"
    16  	"github.com/stretchr/testify/require"
    17  )
    18  
    19  // TestSettleInvoice tests settling of an invoice and related notifications.
    20  func TestSettleInvoice(t *testing.T) {
    21  	ctx := newTestContext(t)
    22  	defer ctx.cleanup()
    23  
    24  	allSubscriptions, err := ctx.registry.SubscribeNotifications(0, 0)
    25  	require.Nil(t, err)
    26  	defer allSubscriptions.Cancel()
    27  
    28  	// Subscribe to the not yet existing invoice.
    29  	subscription, err := ctx.registry.SubscribeSingleInvoice(testInvoicePaymentHash)
    30  	if err != nil {
    31  		t.Fatal(err)
    32  	}
    33  	defer subscription.Cancel()
    34  
    35  	require.Equal(t, subscription.invoiceRef.PayHash(), &testInvoicePaymentHash)
    36  
    37  	// Give enough time for the invoice ntnf goroutine to complete
    38  	time.Sleep(time.Millisecond * 5)
    39  
    40  	// Add the invoice.
    41  	addIdx, err := ctx.registry.AddInvoice(testInvoice, testInvoicePaymentHash)
    42  	if err != nil {
    43  		t.Fatal(err)
    44  	}
    45  
    46  	if addIdx != 1 {
    47  		t.Fatalf("expected addIndex to start with 1, but got %v",
    48  			addIdx)
    49  	}
    50  
    51  	// We expect the open state to be sent to the single invoice subscriber.
    52  	select {
    53  	case update := <-subscription.Updates:
    54  		if update.State != channeldb.ContractOpen {
    55  			t.Fatalf("expected state ContractOpen, but got %v",
    56  				update.State)
    57  		}
    58  	case <-time.After(testTimeout):
    59  		t.Fatal("no update received")
    60  	}
    61  
    62  	// We expect a new invoice notification to be sent out.
    63  	select {
    64  	case newInvoice := <-allSubscriptions.NewInvoices:
    65  		if newInvoice.State != channeldb.ContractOpen {
    66  			t.Fatalf("expected state ContractOpen, but got %v",
    67  				newInvoice.State)
    68  		}
    69  	case <-time.After(testTimeout):
    70  		t.Fatal("no update received")
    71  	}
    72  
    73  	hodlChan := make(chan interface{}, 1)
    74  
    75  	// Try to settle invoice with an htlc that expires too soon.
    76  	resolution, err := ctx.registry.NotifyExitHopHtlc(
    77  		testInvoicePaymentHash, testInvoice.Terms.Value,
    78  		uint32(testCurrentHeight)+testInvoiceCltvDelta-1,
    79  		testCurrentHeight, getCircuitKey(10), hodlChan, testPayload,
    80  	)
    81  	if err != nil {
    82  		t.Fatal(err)
    83  	}
    84  	require.NotNil(t, resolution)
    85  	failResolution := checkFailResolution(
    86  		t, resolution, ResultExpiryTooSoon,
    87  	)
    88  	require.Equal(t, testCurrentHeight, failResolution.AcceptHeight)
    89  
    90  	// Settle invoice with a slightly higher amount.
    91  	amtPaid := lnwire.MilliAtom(100500)
    92  	resolution, err = ctx.registry.NotifyExitHopHtlc(
    93  		testInvoicePaymentHash, amtPaid, testHtlcExpiry,
    94  		testCurrentHeight, getCircuitKey(0), hodlChan,
    95  		testPayload,
    96  	)
    97  	if err != nil {
    98  		t.Fatal(err)
    99  	}
   100  	require.NotNil(t, resolution)
   101  	settleResolution := checkSettleResolution(
   102  		t, resolution, testInvoicePreimage,
   103  	)
   104  	require.Equal(t, ResultSettled, settleResolution.Outcome)
   105  
   106  	// We expect the settled state to be sent to the single invoice
   107  	// subscriber.
   108  	select {
   109  	case update := <-subscription.Updates:
   110  		if update.State != channeldb.ContractSettled {
   111  			t.Fatalf("expected state ContractOpen, but got %v",
   112  				update.State)
   113  		}
   114  		if update.AmtPaid != amtPaid {
   115  			t.Fatal("invoice AmtPaid incorrect")
   116  		}
   117  	case <-time.After(testTimeout):
   118  		t.Fatal("no update received")
   119  	}
   120  
   121  	// We expect a settled notification to be sent out.
   122  	select {
   123  	case settledInvoice := <-allSubscriptions.SettledInvoices:
   124  		if settledInvoice.State != channeldb.ContractSettled {
   125  			t.Fatalf("expected state ContractOpen, but got %v",
   126  				settledInvoice.State)
   127  		}
   128  	case <-time.After(testTimeout):
   129  		t.Fatal("no update received")
   130  	}
   131  
   132  	// Try to settle again with the same htlc id. We need this idempotent
   133  	// behaviour after a restart.
   134  	resolution, err = ctx.registry.NotifyExitHopHtlc(
   135  		testInvoicePaymentHash, amtPaid, testHtlcExpiry, testCurrentHeight,
   136  		getCircuitKey(0), hodlChan, testPayload,
   137  	)
   138  	if err != nil {
   139  		t.Fatalf("unexpected NotifyExitHopHtlc error: %v", err)
   140  	}
   141  	require.NotNil(t, resolution)
   142  	settleResolution = checkSettleResolution(
   143  		t, resolution, testInvoicePreimage,
   144  	)
   145  	require.Equal(t, ResultReplayToSettled, settleResolution.Outcome)
   146  
   147  	// Try to settle again with a new higher-valued htlc. This payment
   148  	// should also be accepted, to prevent any change in behaviour for a
   149  	// paid invoice that may open up a probe vector.
   150  	resolution, err = ctx.registry.NotifyExitHopHtlc(
   151  		testInvoicePaymentHash, amtPaid+600, testHtlcExpiry, testCurrentHeight,
   152  		getCircuitKey(1), hodlChan, testPayload,
   153  	)
   154  	if err != nil {
   155  		t.Fatalf("unexpected NotifyExitHopHtlc error: %v", err)
   156  	}
   157  	require.NotNil(t, resolution)
   158  	settleResolution = checkSettleResolution(
   159  		t, resolution, testInvoicePreimage,
   160  	)
   161  	require.Equal(t, ResultDuplicateToSettled, settleResolution.Outcome)
   162  
   163  	// Try to settle again with a lower amount. This should fail just as it
   164  	// would have failed if it were the first payment.
   165  	resolution, err = ctx.registry.NotifyExitHopHtlc(
   166  		testInvoicePaymentHash, amtPaid-600, testHtlcExpiry, testCurrentHeight,
   167  		getCircuitKey(2), hodlChan, testPayload,
   168  	)
   169  	if err != nil {
   170  		t.Fatalf("unexpected NotifyExitHopHtlc error: %v", err)
   171  	}
   172  	require.NotNil(t, resolution)
   173  	checkFailResolution(t, resolution, ResultAmountTooLow)
   174  
   175  	// Check that settled amount is equal to the sum of values of the htlcs
   176  	// 0 and 1.
   177  	inv, err := ctx.registry.LookupInvoice(testInvoicePaymentHash)
   178  	if err != nil {
   179  		t.Fatal(err)
   180  	}
   181  	if inv.AmtPaid != amtPaid+amtPaid+600 {
   182  		t.Fatalf("amount incorrect: expected %v got %v",
   183  			amtPaid+amtPaid+600, inv.AmtPaid)
   184  	}
   185  
   186  	// Try to cancel.
   187  	err = ctx.registry.CancelInvoice(testInvoicePaymentHash)
   188  	if err != channeldb.ErrInvoiceAlreadySettled {
   189  		t.Fatal("expected cancelation of a settled invoice to fail")
   190  	}
   191  
   192  	// As this is a direct sette, we expect nothing on the hodl chan.
   193  	select {
   194  	case <-hodlChan:
   195  		t.Fatal("unexpected resolution")
   196  	default:
   197  	}
   198  }
   199  
   200  func testCancelInvoice(t *testing.T, gc bool) {
   201  	ctx := newTestContext(t)
   202  	defer ctx.cleanup()
   203  
   204  	// If set to true, then also delete the invoice from the DB after
   205  	// cancellation.
   206  	ctx.registry.cfg.GcCanceledInvoicesOnTheFly = gc
   207  
   208  	allSubscriptions, err := ctx.registry.SubscribeNotifications(0, 0)
   209  	require.Nil(t, err)
   210  	defer allSubscriptions.Cancel()
   211  
   212  	// Try to cancel the not yet existing invoice. This should fail.
   213  	err = ctx.registry.CancelInvoice(testInvoicePaymentHash)
   214  	if err != channeldb.ErrInvoiceNotFound {
   215  		t.Fatalf("expected ErrInvoiceNotFound, but got %v", err)
   216  	}
   217  
   218  	// Subscribe to the not yet existing invoice.
   219  	subscription, err := ctx.registry.SubscribeSingleInvoice(testInvoicePaymentHash)
   220  	if err != nil {
   221  		t.Fatal(err)
   222  	}
   223  	defer subscription.Cancel()
   224  
   225  	require.Equal(t, subscription.invoiceRef.PayHash(), &testInvoicePaymentHash)
   226  
   227  	// Give enough time for the invoice ntnf goroutine to complete
   228  	time.Sleep(time.Millisecond * 5)
   229  
   230  	// Add the invoice.
   231  	amt := lnwire.MilliAtom(100000)
   232  	_, err = ctx.registry.AddInvoice(testInvoice, testInvoicePaymentHash)
   233  	if err != nil {
   234  		t.Fatal(err)
   235  	}
   236  
   237  	// We expect the open state to be sent to the single invoice subscriber.
   238  	select {
   239  	case update := <-subscription.Updates:
   240  		if update.State != channeldb.ContractOpen {
   241  			t.Fatalf(
   242  				"expected state ContractOpen, but got %v",
   243  				update.State,
   244  			)
   245  		}
   246  	case <-time.After(testTimeout):
   247  		t.Fatal("no update received")
   248  	}
   249  
   250  	// We expect a new invoice notification to be sent out.
   251  	select {
   252  	case newInvoice := <-allSubscriptions.NewInvoices:
   253  		if newInvoice.State != channeldb.ContractOpen {
   254  			t.Fatalf(
   255  				"expected state ContractOpen, but got %v",
   256  				newInvoice.State,
   257  			)
   258  		}
   259  	case <-time.After(testTimeout):
   260  		t.Fatal("no update received")
   261  	}
   262  
   263  	// Cancel invoice.
   264  	err = ctx.registry.CancelInvoice(testInvoicePaymentHash)
   265  	if err != nil {
   266  		t.Fatal(err)
   267  	}
   268  
   269  	// We expect the canceled state to be sent to the single invoice
   270  	// subscriber.
   271  	select {
   272  	case update := <-subscription.Updates:
   273  		if update.State != channeldb.ContractCanceled {
   274  			t.Fatalf(
   275  				"expected state ContractCanceled, but got %v",
   276  				update.State,
   277  			)
   278  		}
   279  	case <-time.After(testTimeout):
   280  		t.Fatal("no update received")
   281  	}
   282  
   283  	if gc {
   284  		// Check that the invoice has been deleted from the db.
   285  		_, err = ctx.cdb.LookupInvoice(
   286  			channeldb.InvoiceRefByHash(testInvoicePaymentHash),
   287  		)
   288  		require.Error(t, err)
   289  	}
   290  
   291  	// We expect no cancel notification to be sent to all invoice
   292  	// subscribers (backwards compatibility).
   293  
   294  	// Try to cancel again. Expect that we report ErrInvoiceNotFound if the
   295  	// invoice has been garbage collected (since the invoice has been
   296  	// deleted when it was canceled), and no error otherwise.
   297  	err = ctx.registry.CancelInvoice(testInvoicePaymentHash)
   298  
   299  	if gc {
   300  		require.Error(t, err, channeldb.ErrInvoiceNotFound)
   301  	} else {
   302  		require.NoError(t, err)
   303  	}
   304  
   305  	// Notify arrival of a new htlc paying to this invoice. This should
   306  	// result in a cancel resolution.
   307  	hodlChan := make(chan interface{})
   308  	resolution, err := ctx.registry.NotifyExitHopHtlc(
   309  		testInvoicePaymentHash, amt, testHtlcExpiry, testCurrentHeight,
   310  		getCircuitKey(0), hodlChan, testPayload,
   311  	)
   312  	if err != nil {
   313  		t.Fatal("expected settlement of a canceled invoice to succeed")
   314  	}
   315  	require.NotNil(t, resolution)
   316  
   317  	// If the invoice has been deleted (or not present) then we expect the
   318  	// outcome to be ResultInvoiceNotFound instead of when the invoice is
   319  	// in our database in which case we expect ResultInvoiceAlreadyCanceled.
   320  	var failResolution *HtlcFailResolution
   321  	if gc {
   322  		failResolution = checkFailResolution(
   323  			t, resolution, ResultInvoiceNotFound,
   324  		)
   325  	} else {
   326  		failResolution = checkFailResolution(
   327  			t, resolution, ResultInvoiceAlreadyCanceled,
   328  		)
   329  	}
   330  
   331  	require.Equal(t, testCurrentHeight, failResolution.AcceptHeight)
   332  }
   333  
   334  // TestCancelInvoice tests cancelation of an invoice and related notifications.
   335  func TestCancelInvoice(t *testing.T) {
   336  	// Test cancellation both with garbage collection (meaning that canceled
   337  	// invoice will be deleted) and without (meain it'll be kept).
   338  	t.Run("garbage collect", func(t *testing.T) {
   339  		testCancelInvoice(t, true)
   340  	})
   341  
   342  	t.Run("no garbage collect", func(t *testing.T) {
   343  		testCancelInvoice(t, false)
   344  	})
   345  }
   346  
   347  // TestSettleHoldInvoice tests settling of a hold invoice and related
   348  // notifications.
   349  func TestSettleHoldInvoice(t *testing.T) {
   350  	defer timeout()()
   351  
   352  	cdb, cleanup, err := newTestChannelDB(clock.NewTestClock(time.Time{}))
   353  	if err != nil {
   354  		t.Fatalf("unable to create db: %v", err)
   355  	}
   356  	defer cleanup()
   357  
   358  	// Instantiate and start the invoice ctx.registry.
   359  	cfg := RegistryConfig{
   360  		FinalCltvRejectDelta: testFinalCltvRejectDelta,
   361  		Clock:                clock.NewTestClock(testTime),
   362  	}
   363  
   364  	expiryWatcher := NewInvoiceExpiryWatcher(
   365  		cfg.Clock, 0, uint32(testCurrentHeight), nil, newMockNotifier(),
   366  	)
   367  	registry := NewRegistry(cdb, expiryWatcher, &cfg)
   368  
   369  	err = registry.Start()
   370  	if err != nil {
   371  		t.Fatal(err)
   372  	}
   373  	defer registry.Stop()
   374  
   375  	allSubscriptions, err := registry.SubscribeNotifications(0, 0)
   376  	require.Nil(t, err)
   377  	defer allSubscriptions.Cancel()
   378  
   379  	// Subscribe to the not yet existing invoice.
   380  	subscription, err := registry.SubscribeSingleInvoice(testInvoicePaymentHash)
   381  	if err != nil {
   382  		t.Fatal(err)
   383  	}
   384  	defer subscription.Cancel()
   385  
   386  	require.Equal(t, subscription.invoiceRef.PayHash(), &testInvoicePaymentHash)
   387  
   388  	// Give some time for the subscription to be processed.
   389  	time.Sleep(time.Millisecond * 5)
   390  
   391  	// Add the invoice.
   392  	_, err = registry.AddInvoice(testHodlInvoice, testInvoicePaymentHash)
   393  	if err != nil {
   394  		t.Fatal(err)
   395  	}
   396  
   397  	// We expect the open state to be sent to the single invoice subscriber.
   398  	update := <-subscription.Updates
   399  	if update.State != channeldb.ContractOpen {
   400  		t.Fatalf("expected state ContractOpen, but got %v",
   401  			update.State)
   402  	}
   403  
   404  	// We expect a new invoice notification to be sent out.
   405  	newInvoice := <-allSubscriptions.NewInvoices
   406  	if newInvoice.State != channeldb.ContractOpen {
   407  		t.Fatalf("expected state ContractOpen, but got %v",
   408  			newInvoice.State)
   409  	}
   410  
   411  	// Use slightly higher amount for accept/settle.
   412  	amtPaid := lnwire.MilliAtom(100500)
   413  
   414  	hodlChan := make(chan interface{}, 1)
   415  
   416  	// NotifyExitHopHtlc without a preimage present in the invoice registry
   417  	// should be possible.
   418  	resolution, err := registry.NotifyExitHopHtlc(
   419  		testInvoicePaymentHash, amtPaid, testHtlcExpiry, testCurrentHeight,
   420  		getCircuitKey(0), hodlChan, testPayload,
   421  	)
   422  	if err != nil {
   423  		t.Fatalf("expected settle to succeed but got %v", err)
   424  	}
   425  	if resolution != nil {
   426  		t.Fatalf("expected htlc to be held")
   427  	}
   428  
   429  	// Test idempotency.
   430  	resolution, err = registry.NotifyExitHopHtlc(
   431  		testInvoicePaymentHash, amtPaid, testHtlcExpiry, testCurrentHeight,
   432  		getCircuitKey(0), hodlChan, testPayload,
   433  	)
   434  	if err != nil {
   435  		t.Fatalf("expected settle to succeed but got %v", err)
   436  	}
   437  	if resolution != nil {
   438  		t.Fatalf("expected htlc to be held")
   439  	}
   440  
   441  	// Test replay at a higher height. We expect the same result because it
   442  	// is a replay.
   443  	resolution, err = registry.NotifyExitHopHtlc(
   444  		testInvoicePaymentHash, amtPaid, testHtlcExpiry, testCurrentHeight+10,
   445  		getCircuitKey(0), hodlChan, testPayload,
   446  	)
   447  	if err != nil {
   448  		t.Fatalf("expected settle to succeed but got %v", err)
   449  	}
   450  	if resolution != nil {
   451  		t.Fatalf("expected htlc to be held")
   452  	}
   453  
   454  	// Test a new htlc coming in that doesn't meet the final cltv delta
   455  	// requirement. It should be rejected.
   456  	resolution, err = registry.NotifyExitHopHtlc(
   457  		testInvoicePaymentHash, amtPaid, 1, testCurrentHeight,
   458  		getCircuitKey(1), hodlChan, testPayload,
   459  	)
   460  	if err != nil {
   461  		t.Fatalf("expected settle to succeed but got %v", err)
   462  	}
   463  	require.NotNil(t, resolution)
   464  	checkFailResolution(t, resolution, ResultExpiryTooSoon)
   465  
   466  	// We expect the accepted state to be sent to the single invoice
   467  	// subscriber. For all invoice subscribers, we don't expect an update.
   468  	// Those only get notified on settle.
   469  	update = <-subscription.Updates
   470  	if update.State != channeldb.ContractAccepted {
   471  		t.Fatalf("expected state ContractAccepted, but got %v",
   472  			update.State)
   473  	}
   474  	if update.AmtPaid != amtPaid {
   475  		t.Fatal("invoice AmtPaid incorrect")
   476  	}
   477  
   478  	// Settling with preimage should succeed.
   479  	err = registry.SettleHodlInvoice(testInvoicePreimage)
   480  	if err != nil {
   481  		t.Fatal("expected set preimage to succeed")
   482  	}
   483  
   484  	htlcResolution := (<-hodlChan).(HtlcResolution)
   485  	require.NotNil(t, htlcResolution)
   486  	settleResolution := checkSettleResolution(
   487  		t, htlcResolution, testInvoicePreimage,
   488  	)
   489  	require.Equal(t, testCurrentHeight, settleResolution.AcceptHeight)
   490  	require.Equal(t, ResultSettled, settleResolution.Outcome)
   491  
   492  	// We expect a settled notification to be sent out for both all and
   493  	// single invoice subscribers.
   494  	settledInvoice := <-allSubscriptions.SettledInvoices
   495  	if settledInvoice.State != channeldb.ContractSettled {
   496  		t.Fatalf("expected state ContractSettled, but got %v",
   497  			settledInvoice.State)
   498  	}
   499  	if settledInvoice.AmtPaid != amtPaid {
   500  		t.Fatalf("expected amount to be %v, but got %v",
   501  			amtPaid, settledInvoice.AmtPaid)
   502  	}
   503  
   504  	update = <-subscription.Updates
   505  	if update.State != channeldb.ContractSettled {
   506  		t.Fatalf("expected state ContractSettled, but got %v",
   507  			update.State)
   508  	}
   509  
   510  	// Idempotency.
   511  	err = registry.SettleHodlInvoice(testInvoicePreimage)
   512  	if err != channeldb.ErrInvoiceAlreadySettled {
   513  		t.Fatalf("expected ErrInvoiceAlreadySettled but got %v", err)
   514  	}
   515  
   516  	// Try to cancel.
   517  	err = registry.CancelInvoice(testInvoicePaymentHash)
   518  	if err == nil {
   519  		t.Fatal("expected cancelation of a settled invoice to fail")
   520  	}
   521  }
   522  
   523  // TestCancelHoldInvoice tests canceling of a hold invoice and related
   524  // notifications.
   525  func TestCancelHoldInvoice(t *testing.T) {
   526  	defer timeout()()
   527  
   528  	cdb, cleanup, err := newTestChannelDB(clock.NewTestClock(time.Time{}))
   529  	if err != nil {
   530  		t.Fatal(err)
   531  	}
   532  	defer cleanup()
   533  
   534  	// Instantiate and start the invoice ctx.registry.
   535  	cfg := RegistryConfig{
   536  		FinalCltvRejectDelta: testFinalCltvRejectDelta,
   537  		Clock:                clock.NewTestClock(testTime),
   538  	}
   539  	expiryWatcher := NewInvoiceExpiryWatcher(
   540  		cfg.Clock, 0, uint32(testCurrentHeight), nil, newMockNotifier(),
   541  	)
   542  	registry := NewRegistry(cdb, expiryWatcher, &cfg)
   543  
   544  	err = registry.Start()
   545  	if err != nil {
   546  		t.Fatal(err)
   547  	}
   548  	defer func() {
   549  		if err := registry.Stop(); err != nil {
   550  			t.Fatalf("failed to stop invoice registry: %v", err)
   551  		}
   552  	}()
   553  
   554  	// Add the invoice.
   555  	_, err = registry.AddInvoice(testHodlInvoice, testInvoicePaymentHash)
   556  	if err != nil {
   557  		t.Fatal(err)
   558  	}
   559  
   560  	amtPaid := lnwire.MilliAtom(100000)
   561  	hodlChan := make(chan interface{}, 1)
   562  
   563  	// NotifyExitHopHtlc without a preimage present in the invoice registry
   564  	// should be possible.
   565  	resolution, err := registry.NotifyExitHopHtlc(
   566  		testInvoicePaymentHash, amtPaid, testHtlcExpiry, testCurrentHeight,
   567  		getCircuitKey(0), hodlChan, testPayload,
   568  	)
   569  	if err != nil {
   570  		t.Fatalf("expected settle to succeed but got %v", err)
   571  	}
   572  	if resolution != nil {
   573  		t.Fatalf("expected htlc to be held")
   574  	}
   575  
   576  	// Cancel invoice.
   577  	err = registry.CancelInvoice(testInvoicePaymentHash)
   578  	if err != nil {
   579  		t.Fatal("cancel invoice failed")
   580  	}
   581  
   582  	htlcResolution := (<-hodlChan).(HtlcResolution)
   583  	require.NotNil(t, htlcResolution)
   584  	checkFailResolution(t, htlcResolution, ResultCanceled)
   585  
   586  	// Offering the same htlc again at a higher height should still result
   587  	// in a rejection. The accept height is expected to be the original
   588  	// accept height.
   589  	resolution, err = registry.NotifyExitHopHtlc(
   590  		testInvoicePaymentHash, amtPaid, testHtlcExpiry, testCurrentHeight+1,
   591  		getCircuitKey(0), hodlChan, testPayload,
   592  	)
   593  	if err != nil {
   594  		t.Fatalf("expected settle to succeed but got %v", err)
   595  	}
   596  	require.NotNil(t, resolution)
   597  	failResolution := checkFailResolution(
   598  		t, resolution, ResultReplayToCanceled,
   599  	)
   600  	require.Equal(t, testCurrentHeight, failResolution.AcceptHeight)
   601  }
   602  
   603  // TestUnknownInvoice tests that invoice registry returns an error when the
   604  // invoice is unknown. This is to guard against returning a cancel htlc
   605  // resolution for forwarded htlcs. In the link, NotifyExitHopHtlc is only called
   606  // if we are the exit hop, but in htlcIncomingContestResolver it is called with
   607  // forwarded htlc hashes as well.
   608  func TestUnknownInvoice(t *testing.T) {
   609  	ctx := newTestContext(t)
   610  	defer ctx.cleanup()
   611  
   612  	// Notify arrival of a new htlc paying to this invoice. This should
   613  	// succeed.
   614  	hodlChan := make(chan interface{})
   615  	amt := lnwire.MilliAtom(100000)
   616  	resolution, err := ctx.registry.NotifyExitHopHtlc(
   617  		testInvoicePaymentHash, amt, testHtlcExpiry, testCurrentHeight,
   618  		getCircuitKey(0), hodlChan, testPayload,
   619  	)
   620  	if err != nil {
   621  		t.Fatal("unexpected error")
   622  	}
   623  	require.NotNil(t, resolution)
   624  	checkFailResolution(t, resolution, ResultInvoiceNotFound)
   625  }
   626  
   627  // TestKeySend tests receiving a spontaneous payment with and without keysend
   628  // enabled.
   629  func TestKeySend(t *testing.T) {
   630  	t.Run("enabled", func(t *testing.T) {
   631  		testKeySend(t, true)
   632  	})
   633  	t.Run("disabled", func(t *testing.T) {
   634  		testKeySend(t, false)
   635  	})
   636  }
   637  
   638  // testKeySend is the inner test function that tests keysend for a particular
   639  // enabled state on the receiver end.
   640  func testKeySend(t *testing.T, keySendEnabled bool) {
   641  	defer timeout()()
   642  
   643  	ctx := newTestContext(t)
   644  	defer ctx.cleanup()
   645  
   646  	ctx.registry.cfg.AcceptKeySend = keySendEnabled
   647  
   648  	allSubscriptions, err := ctx.registry.SubscribeNotifications(0, 0)
   649  	require.Nil(t, err)
   650  	defer allSubscriptions.Cancel()
   651  
   652  	hodlChan := make(chan interface{}, 1)
   653  
   654  	amt := lnwire.MilliAtom(1000)
   655  	expiry := uint32(testCurrentHeight + 20)
   656  
   657  	// Create key for keysend.
   658  	preimage := lntypes.Preimage{1, 2, 3}
   659  	hash := preimage.Hash()
   660  
   661  	// Try to settle invoice with an invalid keysend htlc.
   662  	invalidKeySendPayload := &mockPayload{
   663  		customRecords: map[uint64][]byte{
   664  			record.KeySendType: {1, 2, 3},
   665  		},
   666  	}
   667  
   668  	resolution, err := ctx.registry.NotifyExitHopHtlc(
   669  		hash, amt, expiry,
   670  		testCurrentHeight, getCircuitKey(10), hodlChan,
   671  		invalidKeySendPayload,
   672  	)
   673  	if err != nil {
   674  		t.Fatal(err)
   675  	}
   676  	require.NotNil(t, resolution)
   677  
   678  	if !keySendEnabled {
   679  		checkFailResolution(t, resolution, ResultInvoiceNotFound)
   680  	} else {
   681  		checkFailResolution(t, resolution, ResultKeySendError)
   682  	}
   683  
   684  	// Try to settle invoice with a valid keysend htlc.
   685  	keySendPayload := &mockPayload{
   686  		customRecords: map[uint64][]byte{
   687  			record.KeySendType: preimage[:],
   688  		},
   689  	}
   690  
   691  	resolution, err = ctx.registry.NotifyExitHopHtlc(
   692  		hash, amt, expiry,
   693  		testCurrentHeight, getCircuitKey(10), hodlChan, keySendPayload,
   694  	)
   695  	if err != nil {
   696  		t.Fatal(err)
   697  	}
   698  
   699  	// Expect a cancel resolution if keysend is disabled.
   700  	if !keySendEnabled {
   701  		checkFailResolution(t, resolution, ResultInvoiceNotFound)
   702  		return
   703  	}
   704  
   705  	checkSubscription := func() {
   706  		// We expect a new invoice notification to be sent out.
   707  		newInvoice := <-allSubscriptions.NewInvoices
   708  		require.Equal(t, newInvoice.State, channeldb.ContractOpen)
   709  
   710  		// We expect a settled notification to be sent out.
   711  		settledInvoice := <-allSubscriptions.SettledInvoices
   712  		require.Equal(t, settledInvoice.State, channeldb.ContractSettled)
   713  	}
   714  
   715  	checkSettleResolution(t, resolution, preimage)
   716  	checkSubscription()
   717  
   718  	// Replay the same keysend payment. We expect an identical resolution,
   719  	// but no event should be generated.
   720  	resolution, err = ctx.registry.NotifyExitHopHtlc(
   721  		hash, amt, expiry,
   722  		testCurrentHeight, getCircuitKey(10), hodlChan, keySendPayload,
   723  	)
   724  	require.Nil(t, err)
   725  	checkSettleResolution(t, resolution, preimage)
   726  
   727  	select {
   728  	case <-allSubscriptions.NewInvoices:
   729  		t.Fatalf("replayed keysend should not generate event")
   730  	case <-time.After(time.Second):
   731  	}
   732  
   733  	// Finally, test that we can properly fulfill a second keysend payment
   734  	// with a unique preiamge.
   735  	preimage2 := lntypes.Preimage{1, 2, 3, 4}
   736  	hash2 := preimage2.Hash()
   737  
   738  	keySendPayload2 := &mockPayload{
   739  		customRecords: map[uint64][]byte{
   740  			record.KeySendType: preimage2[:],
   741  		},
   742  	}
   743  
   744  	resolution, err = ctx.registry.NotifyExitHopHtlc(
   745  		hash2, amt, expiry,
   746  		testCurrentHeight, getCircuitKey(20), hodlChan, keySendPayload2,
   747  	)
   748  	require.Nil(t, err)
   749  
   750  	checkSettleResolution(t, resolution, preimage2)
   751  	checkSubscription()
   752  }
   753  
   754  // TestHoldKeysend tests receiving a spontaneous payment that is held.
   755  func TestHoldKeysend(t *testing.T) {
   756  	t.Run("settle", func(t *testing.T) {
   757  		testHoldKeysend(t, false)
   758  	})
   759  	t.Run("timeout", func(t *testing.T) {
   760  		testHoldKeysend(t, true)
   761  	})
   762  }
   763  
   764  // testHoldKeysend is the inner test function that tests hold-keysend.
   765  func testHoldKeysend(t *testing.T, timeoutKeysend bool) {
   766  	defer timeout()()
   767  
   768  	const holdDuration = time.Minute
   769  
   770  	ctx := newTestContext(t)
   771  	defer ctx.cleanup()
   772  
   773  	ctx.registry.cfg.AcceptKeySend = true
   774  	ctx.registry.cfg.KeysendHoldTime = holdDuration
   775  
   776  	allSubscriptions, err := ctx.registry.SubscribeNotifications(0, 0)
   777  	require.Nil(t, err)
   778  	defer allSubscriptions.Cancel()
   779  
   780  	hodlChan := make(chan interface{}, 1)
   781  
   782  	amt := lnwire.MilliAtom(1000)
   783  	expiry := uint32(testCurrentHeight + 20)
   784  
   785  	// Create key for keysend.
   786  	preimage := lntypes.Preimage{1, 2, 3}
   787  	hash := preimage.Hash()
   788  
   789  	// Try to settle invoice with a valid keysend htlc.
   790  	keysendPayload := &mockPayload{
   791  		customRecords: map[uint64][]byte{
   792  			record.KeySendType: preimage[:],
   793  		},
   794  	}
   795  
   796  	resolution, err := ctx.registry.NotifyExitHopHtlc(
   797  		hash, amt, expiry,
   798  		testCurrentHeight, getCircuitKey(10), hodlChan, keysendPayload,
   799  	)
   800  	if err != nil {
   801  		t.Fatal(err)
   802  	}
   803  
   804  	// No immediate resolution is expected.
   805  	require.Nil(t, resolution, "expected hold resolution")
   806  
   807  	// We expect a new invoice notification to be sent out.
   808  	newInvoice := <-allSubscriptions.NewInvoices
   809  	if newInvoice.State != channeldb.ContractOpen {
   810  		t.Fatalf("expected state ContractOpen, but got %v",
   811  			newInvoice.State)
   812  	}
   813  
   814  	// We expect no further invoice notifications yet (on the all invoices
   815  	// subscription).
   816  	select {
   817  	case <-allSubscriptions.NewInvoices:
   818  		t.Fatalf("no invoice update expected")
   819  	case <-time.After(100 * time.Millisecond):
   820  	}
   821  
   822  	if timeoutKeysend {
   823  		// Advance the clock to just past the hold duration.
   824  		ctx.clock.SetTime(ctx.clock.Now().Add(
   825  			holdDuration + time.Millisecond),
   826  		)
   827  
   828  		// Expect the keysend payment to be failed.
   829  		res := <-hodlChan
   830  		failResolution, ok := res.(*HtlcFailResolution)
   831  		require.Truef(
   832  			t, ok, "expected fail resolution, got: %T",
   833  			resolution,
   834  		)
   835  		require.Equal(
   836  			t, ResultCanceled, failResolution.Outcome,
   837  			"expected keysend payment to be failed",
   838  		)
   839  
   840  		return
   841  	}
   842  
   843  	// Settle keysend payment manually.
   844  	require.Nil(t, ctx.registry.SettleHodlInvoice(
   845  		*newInvoice.Terms.PaymentPreimage,
   846  	))
   847  
   848  	// We expect a settled notification to be sent out.
   849  	settledInvoice := <-allSubscriptions.SettledInvoices
   850  	require.Equal(t, settledInvoice.State, channeldb.ContractSettled)
   851  }
   852  
   853  // TestMppPayment tests settling of an invoice with multiple partial payments.
   854  // It covers the case where there is a mpp timeout before the whole invoice is
   855  // paid and the case where the invoice is settled in time.
   856  func TestMppPayment(t *testing.T) {
   857  	defer timeout()()
   858  
   859  	ctx := newTestContext(t)
   860  	defer ctx.cleanup()
   861  
   862  	// Add the invoice.
   863  	_, err := ctx.registry.AddInvoice(testInvoice, testInvoicePaymentHash)
   864  	if err != nil {
   865  		t.Fatal(err)
   866  	}
   867  
   868  	mppPayload := &mockPayload{
   869  		mpp: record.NewMPP(testInvoiceAmt, [32]byte{}),
   870  	}
   871  
   872  	// Send htlc 1.
   873  	hodlChan1 := make(chan interface{}, 1)
   874  	resolution, err := ctx.registry.NotifyExitHopHtlc(
   875  		testInvoicePaymentHash, testInvoice.Terms.Value/2,
   876  		testHtlcExpiry,
   877  		testCurrentHeight, getCircuitKey(10), hodlChan1, mppPayload,
   878  	)
   879  	if err != nil {
   880  		t.Fatal(err)
   881  	}
   882  	if resolution != nil {
   883  		t.Fatal("expected no direct resolution")
   884  	}
   885  
   886  	// Simulate mpp timeout releasing htlc 1.
   887  	ctx.clock.SetTime(testTime.Add(30 * time.Second))
   888  
   889  	htlcResolution := (<-hodlChan1).(HtlcResolution)
   890  	failResolution, ok := htlcResolution.(*HtlcFailResolution)
   891  	if !ok {
   892  		t.Fatalf("expected fail resolution, got: %T",
   893  			resolution)
   894  	}
   895  	if failResolution.Outcome != ResultMppTimeout {
   896  		t.Fatalf("expected mpp timeout, got: %v",
   897  			failResolution.Outcome)
   898  	}
   899  
   900  	// Send htlc 2.
   901  	hodlChan2 := make(chan interface{}, 1)
   902  	resolution, err = ctx.registry.NotifyExitHopHtlc(
   903  		testInvoicePaymentHash, testInvoice.Terms.Value/2,
   904  		testHtlcExpiry,
   905  		testCurrentHeight, getCircuitKey(11), hodlChan2, mppPayload,
   906  	)
   907  	if err != nil {
   908  		t.Fatal(err)
   909  	}
   910  	if resolution != nil {
   911  		t.Fatal("expected no direct resolution")
   912  	}
   913  
   914  	// Send htlc 3.
   915  	hodlChan3 := make(chan interface{}, 1)
   916  	resolution, err = ctx.registry.NotifyExitHopHtlc(
   917  		testInvoicePaymentHash, testInvoice.Terms.Value/2,
   918  		testHtlcExpiry,
   919  		testCurrentHeight, getCircuitKey(12), hodlChan3, mppPayload,
   920  	)
   921  	if err != nil {
   922  		t.Fatal(err)
   923  	}
   924  	settleResolution, ok := resolution.(*HtlcSettleResolution)
   925  	if !ok {
   926  		t.Fatalf("expected settle resolution, got: %T",
   927  			htlcResolution)
   928  	}
   929  	if settleResolution.Outcome != ResultSettled {
   930  		t.Fatalf("expected result settled, got: %v",
   931  			settleResolution.Outcome)
   932  	}
   933  
   934  	// Check that settled amount is equal to the sum of values of the htlcs
   935  	// 2 and 3.
   936  	inv, err := ctx.registry.LookupInvoice(testInvoicePaymentHash)
   937  	if err != nil {
   938  		t.Fatal(err)
   939  	}
   940  	if inv.State != channeldb.ContractSettled {
   941  		t.Fatal("expected invoice to be settled")
   942  	}
   943  	if inv.AmtPaid != testInvoice.Terms.Value {
   944  		t.Fatalf("amount incorrect, expected %v but got %v",
   945  			testInvoice.Terms.Value, inv.AmtPaid)
   946  	}
   947  }
   948  
   949  // Tests that invoices are canceled after expiration.
   950  func TestInvoiceExpiryWithRegistry(t *testing.T) {
   951  	t.Parallel()
   952  
   953  	cdb, cleanup, err := newTestChannelDB(clock.NewTestClock(time.Time{}))
   954  	defer cleanup()
   955  
   956  	if err != nil {
   957  		t.Fatal(err)
   958  	}
   959  
   960  	testClock := clock.NewTestClock(testTime)
   961  
   962  	cfg := RegistryConfig{
   963  		FinalCltvRejectDelta: testFinalCltvRejectDelta,
   964  		Clock:                testClock,
   965  	}
   966  
   967  	expiryWatcher := NewInvoiceExpiryWatcher(
   968  		cfg.Clock, 0, uint32(testCurrentHeight), nil, newMockNotifier(),
   969  	)
   970  	registry := NewRegistry(cdb, expiryWatcher, &cfg)
   971  
   972  	// First prefill the Channel DB with some pre-existing invoices,
   973  	// half of them still pending, half of them expired.
   974  	const numExpired = 5
   975  	const numPending = 5
   976  	existingInvoices := generateInvoiceExpiryTestData(
   977  		t, testTime, 0, numExpired, numPending,
   978  	)
   979  
   980  	var expectedCancellations []lntypes.Hash
   981  
   982  	for paymentHash, expiredInvoice := range existingInvoices.expiredInvoices {
   983  		if _, err := cdb.AddInvoice(expiredInvoice, paymentHash); err != nil {
   984  			t.Fatalf("cannot add invoice to channel db: %v", err)
   985  		}
   986  		expectedCancellations = append(expectedCancellations, paymentHash)
   987  	}
   988  
   989  	for paymentHash, pendingInvoice := range existingInvoices.pendingInvoices {
   990  		if _, err := cdb.AddInvoice(pendingInvoice, paymentHash); err != nil {
   991  			t.Fatalf("cannot add invoice to channel db: %v", err)
   992  		}
   993  	}
   994  
   995  	if err = registry.Start(); err != nil {
   996  		t.Fatalf("cannot start registry: %v", err)
   997  	}
   998  
   999  	// Now generate pending and invoices and add them to the registry while
  1000  	// it is up and running. We'll manipulate the clock to let them expire.
  1001  	newInvoices := generateInvoiceExpiryTestData(
  1002  		t, testTime, numExpired+numPending, 0, numPending,
  1003  	)
  1004  
  1005  	var invoicesThatWillCancel []lntypes.Hash
  1006  	for paymentHash, pendingInvoice := range newInvoices.pendingInvoices {
  1007  		_, err := registry.AddInvoice(pendingInvoice, paymentHash)
  1008  		invoicesThatWillCancel = append(invoicesThatWillCancel, paymentHash)
  1009  		if err != nil {
  1010  			t.Fatal(err)
  1011  		}
  1012  	}
  1013  
  1014  	// Check that they are really not canceled until before the clock is
  1015  	// advanced.
  1016  	for i := range invoicesThatWillCancel {
  1017  		invoice, err := registry.LookupInvoice(invoicesThatWillCancel[i])
  1018  		if err != nil {
  1019  			t.Fatalf("cannot find invoice: %v", err)
  1020  		}
  1021  
  1022  		if invoice.State == channeldb.ContractCanceled {
  1023  			t.Fatalf("expected pending invoice, got canceled")
  1024  		}
  1025  	}
  1026  
  1027  	// Fwd time 1 day.
  1028  	testClock.SetTime(testTime.Add(24 * time.Hour))
  1029  
  1030  	// Give some time to the watcher to cancel everything.
  1031  	time.Sleep(500 * time.Millisecond)
  1032  	if err = registry.Stop(); err != nil {
  1033  		t.Fatalf("failed to stop invoice registry: %v", err)
  1034  	}
  1035  
  1036  	// Create the expected cancellation set before the final check.
  1037  	expectedCancellations = append(
  1038  		expectedCancellations, invoicesThatWillCancel...,
  1039  	)
  1040  
  1041  	// Retrospectively check that all invoices that were expected to be canceled
  1042  	// are indeed canceled.
  1043  	for i := range expectedCancellations {
  1044  		invoice, err := registry.LookupInvoice(expectedCancellations[i])
  1045  		if err != nil {
  1046  			t.Fatalf("cannot find invoice: %v", err)
  1047  		}
  1048  
  1049  		if invoice.State != channeldb.ContractCanceled {
  1050  			t.Fatalf("expected canceled invoice, got: %v", invoice.State)
  1051  		}
  1052  	}
  1053  }
  1054  
  1055  // TestOldInvoiceRemovalOnStart tests that we'll attempt to remove old canceled
  1056  // invoices upon start while keeping all settled ones.
  1057  func TestOldInvoiceRemovalOnStart(t *testing.T) {
  1058  	t.Parallel()
  1059  
  1060  	testClock := clock.NewTestClock(testTime)
  1061  	cdb, cleanup, err := newTestChannelDB(testClock)
  1062  	defer cleanup()
  1063  
  1064  	require.NoError(t, err)
  1065  
  1066  	cfg := RegistryConfig{
  1067  		FinalCltvRejectDelta:        testFinalCltvRejectDelta,
  1068  		Clock:                       testClock,
  1069  		GcCanceledInvoicesOnStartup: true,
  1070  	}
  1071  
  1072  	expiryWatcher := NewInvoiceExpiryWatcher(
  1073  		cfg.Clock, 0, uint32(testCurrentHeight), nil, newMockNotifier(),
  1074  	)
  1075  	registry := NewRegistry(cdb, expiryWatcher, &cfg)
  1076  
  1077  	// First prefill the Channel DB with some pre-existing expired invoices.
  1078  	const numExpired = 5
  1079  	const numPending = 0
  1080  	existingInvoices := generateInvoiceExpiryTestData(
  1081  		t, testTime, 0, numExpired, numPending,
  1082  	)
  1083  
  1084  	i := 0
  1085  	for paymentHash, invoice := range existingInvoices.expiredInvoices {
  1086  		// Mark half of the invoices as settled, the other hald as
  1087  		// canceled.
  1088  		if i%2 == 0 {
  1089  			invoice.State = channeldb.ContractSettled
  1090  		} else {
  1091  			invoice.State = channeldb.ContractCanceled
  1092  		}
  1093  
  1094  		_, err := cdb.AddInvoice(invoice, paymentHash)
  1095  		require.NoError(t, err)
  1096  		i++
  1097  	}
  1098  
  1099  	// Collect all settled invoices for our expectation set.
  1100  	var expected []channeldb.Invoice
  1101  
  1102  	// Perform a scan query to collect all invoices.
  1103  	query := channeldb.InvoiceQuery{
  1104  		IndexOffset:    0,
  1105  		NumMaxInvoices: math.MaxUint64,
  1106  	}
  1107  
  1108  	response, err := cdb.QueryInvoices(query)
  1109  	require.NoError(t, err)
  1110  
  1111  	// Save all settled invoices for our expectation set.
  1112  	for _, invoice := range response.Invoices {
  1113  		if invoice.State == channeldb.ContractSettled {
  1114  			expected = append(expected, invoice)
  1115  		}
  1116  	}
  1117  
  1118  	// Start the registry which should collect and delete all canceled
  1119  	// invoices upon start.
  1120  	err = registry.Start()
  1121  	require.NoError(t, err, "cannot start the registry")
  1122  
  1123  	// Perform a scan query to collect all invoices.
  1124  	response, err = cdb.QueryInvoices(query)
  1125  	require.NoError(t, err)
  1126  
  1127  	// Check that we really only kept the settled invoices after the
  1128  	// registry start.
  1129  	require.Equal(t, expected, response.Invoices)
  1130  }
  1131  
  1132  // TestHeightExpiryWithRegistry tests our height-based invoice expiry for
  1133  // invoices paid with single and multiple htlcs, testing the case where the
  1134  // invoice is settled before expiry (and thus not canceled), and the case
  1135  // where the invoice is expired.
  1136  func TestHeightExpiryWithRegistry(t *testing.T) {
  1137  	t.Run("single shot settled before expiry", func(t *testing.T) {
  1138  		testHeightExpiryWithRegistry(t, 1, true)
  1139  	})
  1140  
  1141  	t.Run("single shot expires", func(t *testing.T) {
  1142  		testHeightExpiryWithRegistry(t, 1, false)
  1143  	})
  1144  
  1145  	t.Run("mpp settled before expiry", func(t *testing.T) {
  1146  		testHeightExpiryWithRegistry(t, 2, true)
  1147  	})
  1148  
  1149  	t.Run("mpp expires", func(t *testing.T) {
  1150  		testHeightExpiryWithRegistry(t, 2, false)
  1151  	})
  1152  }
  1153  
  1154  func testHeightExpiryWithRegistry(t *testing.T, numParts int, settle bool) {
  1155  	t.Parallel()
  1156  	defer timeout()()
  1157  
  1158  	ctx := newTestContext(t)
  1159  	defer ctx.cleanup()
  1160  
  1161  	require.Greater(t, numParts, 0, "test requires at least one part")
  1162  
  1163  	// Add a hold invoice, we set a non-nil payment request so that this
  1164  	// invoice is not considered a keysend by the expiry watcher.
  1165  	invoice := *testInvoice
  1166  	invoice.HodlInvoice = true
  1167  	invoice.PaymentRequest = []byte{1, 2, 3}
  1168  
  1169  	_, err := ctx.registry.AddInvoice(&invoice, testInvoicePaymentHash)
  1170  	require.NoError(t, err)
  1171  
  1172  	payLoad := testPayload
  1173  	if numParts > 1 {
  1174  		payLoad = &mockPayload{
  1175  			mpp: record.NewMPP(testInvoiceAmt, [32]byte{}),
  1176  		}
  1177  	}
  1178  
  1179  	htlcAmt := invoice.Terms.Value / lnwire.MilliAtom(numParts)
  1180  	hodlChan := make(chan interface{}, numParts)
  1181  	for i := 0; i < numParts; i++ {
  1182  		// We bump our expiry height for each htlc so that we can test
  1183  		// that the lowest expiry height is used.
  1184  		expiry := testHtlcExpiry + uint32(i)
  1185  
  1186  		resolution, err := ctx.registry.NotifyExitHopHtlc(
  1187  			testInvoicePaymentHash, htlcAmt, expiry,
  1188  			testCurrentHeight, getCircuitKey(uint64(i)), hodlChan,
  1189  			payLoad,
  1190  		)
  1191  		require.NoError(t, err)
  1192  		require.Nil(t, resolution, "did not expect direct resolution")
  1193  	}
  1194  
  1195  	require.Eventually(t, func() bool {
  1196  		inv, err := ctx.registry.LookupInvoice(testInvoicePaymentHash)
  1197  		require.NoError(t, err)
  1198  
  1199  		return inv.State == channeldb.ContractAccepted
  1200  	}, time.Second, time.Millisecond*100)
  1201  
  1202  	// Now that we've added our htlc(s), we tick our test clock to our
  1203  	// invoice expiry time. We don't expect the invoice to be canceled
  1204  	// based on its expiry time now that we have active htlcs.
  1205  	ctx.clock.SetTime(invoice.CreationDate.Add(invoice.Terms.Expiry + 1))
  1206  
  1207  	// The expiry watcher loop takes some time to process the new clock
  1208  	// time. We mine the block before our expiry height, our mock will block
  1209  	// until the expiry watcher consumes this height, so we can be sure
  1210  	// that the expiry loop has run at least once after this block is
  1211  	// consumed.
  1212  	ctx.notifier.blockChan <- &chainntnfs.BlockEpoch{
  1213  		Height: int32(testHtlcExpiry - 1),
  1214  	}
  1215  
  1216  	// If we want to settle our invoice in this test, we do so now.
  1217  	if settle {
  1218  		err = ctx.registry.SettleHodlInvoice(testInvoicePreimage)
  1219  		require.NoError(t, err)
  1220  
  1221  		for i := 0; i < numParts; i++ {
  1222  			htlcResolution := (<-hodlChan).(HtlcResolution)
  1223  			require.NotNil(t, htlcResolution)
  1224  			settleResolution := checkSettleResolution(
  1225  				t, htlcResolution, testInvoicePreimage,
  1226  			)
  1227  			require.Equal(t, ResultSettled, settleResolution.Outcome)
  1228  		}
  1229  	}
  1230  
  1231  	// Now we mine our htlc's expiry height.
  1232  	ctx.notifier.blockChan <- &chainntnfs.BlockEpoch{
  1233  		Height: int32(testHtlcExpiry),
  1234  	}
  1235  
  1236  	// If we did not settle the invoice before its expiry, we now expect
  1237  	// a cancelation.
  1238  	expectedState := channeldb.ContractSettled
  1239  	if !settle {
  1240  		expectedState = channeldb.ContractCanceled
  1241  
  1242  		htlcResolution := (<-hodlChan).(HtlcResolution)
  1243  		require.NotNil(t, htlcResolution)
  1244  		checkFailResolution(
  1245  			t, htlcResolution, ResultCanceled,
  1246  		)
  1247  	}
  1248  
  1249  	// Finally, lookup the invoice and assert that we have the state we
  1250  	// expect.
  1251  	inv, err := ctx.registry.LookupInvoice(testInvoicePaymentHash)
  1252  	require.NoError(t, err)
  1253  	require.Equal(t, expectedState, inv.State, "expected "+
  1254  		"hold invoice: %v, got: %v", expectedState, inv.State)
  1255  }
  1256  
  1257  // TestMultipleSetHeightExpiry pays a hold invoice with two mpp sets, testing
  1258  // that the invoice expiry watcher only uses the expiry height of the second,
  1259  // successful set to cancel the invoice, and does not cancel early using the
  1260  // expiry height of the first set that was canceled back due to mpp timeout.
  1261  func TestMultipleSetHeightExpiry(t *testing.T) {
  1262  	t.Parallel()
  1263  	defer timeout()()
  1264  
  1265  	ctx := newTestContext(t)
  1266  	defer ctx.cleanup()
  1267  
  1268  	// Add a hold invoice.
  1269  	invoice := *testInvoice
  1270  	invoice.HodlInvoice = true
  1271  
  1272  	_, err := ctx.registry.AddInvoice(&invoice, testInvoicePaymentHash)
  1273  	require.NoError(t, err)
  1274  
  1275  	mppPayload := &mockPayload{
  1276  		mpp: record.NewMPP(testInvoiceAmt, [32]byte{}),
  1277  	}
  1278  
  1279  	// Send htlc 1.
  1280  	hodlChan1 := make(chan interface{}, 1)
  1281  	resolution, err := ctx.registry.NotifyExitHopHtlc(
  1282  		testInvoicePaymentHash, invoice.Terms.Value/2,
  1283  		testHtlcExpiry,
  1284  		testCurrentHeight, getCircuitKey(10), hodlChan1, mppPayload,
  1285  	)
  1286  	require.NoError(t, err)
  1287  	require.Nil(t, resolution, "did not expect direct resolution")
  1288  
  1289  	// Simulate mpp timeout releasing htlc 1.
  1290  	ctx.clock.SetTime(testTime.Add(30 * time.Second))
  1291  
  1292  	htlcResolution := (<-hodlChan1).(HtlcResolution)
  1293  	failResolution, ok := htlcResolution.(*HtlcFailResolution)
  1294  	require.True(t, ok, "expected fail resolution, got: %T", resolution)
  1295  	require.Equal(t, ResultMppTimeout, failResolution.Outcome,
  1296  		"expected MPP Timeout, got: %v", failResolution.Outcome)
  1297  
  1298  	// Notify the expiry height for our first htlc. We don't expect the
  1299  	// invoice to be expired based on block height because the htlc set
  1300  	// was never completed.
  1301  	ctx.notifier.blockChan <- &chainntnfs.BlockEpoch{
  1302  		Height: int32(testHtlcExpiry),
  1303  	}
  1304  
  1305  	// Now we will send a full set of htlcs for the invoice with a higher
  1306  	// expiry height. We expect the invoice to move into the accepted state.
  1307  	expiry := testHtlcExpiry + 5
  1308  
  1309  	// Send htlc 2.
  1310  	hodlChan2 := make(chan interface{}, 1)
  1311  	resolution, err = ctx.registry.NotifyExitHopHtlc(
  1312  		testInvoicePaymentHash, invoice.Terms.Value/2, expiry,
  1313  		testCurrentHeight, getCircuitKey(11), hodlChan2, mppPayload,
  1314  	)
  1315  	require.NoError(t, err)
  1316  	require.Nil(t, resolution, "did not expect direct resolution")
  1317  
  1318  	// Send htlc 3.
  1319  	hodlChan3 := make(chan interface{}, 1)
  1320  	resolution, err = ctx.registry.NotifyExitHopHtlc(
  1321  		testInvoicePaymentHash, invoice.Terms.Value/2, expiry,
  1322  		testCurrentHeight, getCircuitKey(12), hodlChan3, mppPayload,
  1323  	)
  1324  	require.NoError(t, err)
  1325  	require.Nil(t, resolution, "did not expect direct resolution")
  1326  
  1327  	// Assert that we've reached an accepted state because the invoice has
  1328  	// been paid with a complete set.
  1329  	inv, err := ctx.registry.LookupInvoice(testInvoicePaymentHash)
  1330  	require.NoError(t, err)
  1331  	require.Equal(t, channeldb.ContractAccepted, inv.State, "expected "+
  1332  		"hold invoice accepted")
  1333  
  1334  	// Now we will notify the expiry height for the new set of htlcs. We
  1335  	// expect the invoice to be canceled by the expiry watcher.
  1336  	ctx.notifier.blockChan <- &chainntnfs.BlockEpoch{
  1337  		Height: int32(expiry),
  1338  	}
  1339  
  1340  	require.Eventuallyf(t, func() bool {
  1341  		inv, err := ctx.registry.LookupInvoice(testInvoicePaymentHash)
  1342  		require.NoError(t, err)
  1343  
  1344  		return inv.State == channeldb.ContractCanceled
  1345  	}, testTimeout, time.Millisecond*100, "invoice not canceled")
  1346  }
  1347  
  1348  // TestSettleInvoicePaymentAddrRequired tests that if an incoming payment has
  1349  // an invoice that requires the payment addr bit to be set, and the incoming
  1350  // payment doesn't include an mpp payload, then the payment is rejected.
  1351  func TestSettleInvoicePaymentAddrRequired(t *testing.T) {
  1352  	t.Parallel()
  1353  
  1354  	ctx := newTestContext(t)
  1355  	defer ctx.cleanup()
  1356  
  1357  	allSubscriptions, err := ctx.registry.SubscribeNotifications(0, 0)
  1358  	require.Nil(t, err)
  1359  	defer allSubscriptions.Cancel()
  1360  
  1361  	// Subscribe to the not yet existing invoice.
  1362  	subscription, err := ctx.registry.SubscribeSingleInvoice(
  1363  		testInvoicePaymentHash,
  1364  	)
  1365  	require.NoError(t, err)
  1366  	defer subscription.Cancel()
  1367  
  1368  	require.Equal(
  1369  		t, subscription.invoiceRef.PayHash(), &testInvoicePaymentHash,
  1370  	)
  1371  
  1372  	// Add the invoice, which requires the MPP payload to always be
  1373  	// included due to its set of feature bits.
  1374  	addIdx, err := ctx.registry.AddInvoice(
  1375  		testPayAddrReqInvoice, testInvoicePaymentHash,
  1376  	)
  1377  	require.NoError(t, err)
  1378  	require.Equal(t, int(addIdx), 1)
  1379  
  1380  	// We expect the open state to be sent to the single invoice subscriber.
  1381  	select {
  1382  	case update := <-subscription.Updates:
  1383  		if update.State != channeldb.ContractOpen {
  1384  			t.Fatalf("expected state ContractOpen, but got %v",
  1385  				update.State)
  1386  		}
  1387  	case <-time.After(testTimeout):
  1388  		t.Fatal("no update received")
  1389  	}
  1390  
  1391  	// We expect a new invoice notification to be sent out.
  1392  	select {
  1393  	case newInvoice := <-allSubscriptions.NewInvoices:
  1394  		if newInvoice.State != channeldb.ContractOpen {
  1395  			t.Fatalf("expected state ContractOpen, but got %v",
  1396  				newInvoice.State)
  1397  		}
  1398  	case <-time.After(testTimeout):
  1399  		t.Fatal("no update received")
  1400  	}
  1401  
  1402  	hodlChan := make(chan interface{}, 1)
  1403  
  1404  	// Now try to settle the invoice, the testPayload doesn't have any mpp
  1405  	// information, so it should be forced to the updateLegacy path then
  1406  	// fail as a required feature bit exists.
  1407  	resolution, err := ctx.registry.NotifyExitHopHtlc(
  1408  		testInvoicePaymentHash, testInvoice.Terms.Value,
  1409  		uint32(testCurrentHeight)+testInvoiceCltvDelta-1,
  1410  		testCurrentHeight, getCircuitKey(10), hodlChan, testPayload,
  1411  	)
  1412  	require.NoError(t, err)
  1413  
  1414  	failResolution, ok := resolution.(*HtlcFailResolution)
  1415  	if !ok {
  1416  		t.Fatalf("expected fail resolution, got: %T",
  1417  			resolution)
  1418  	}
  1419  	require.Equal(t, failResolution.AcceptHeight, testCurrentHeight)
  1420  	require.Equal(t, failResolution.Outcome, ResultAddressMismatch)
  1421  }
  1422  
  1423  // TestSettleInvoicePaymentAddrRequiredOptionalGrace tests that if an invoice
  1424  // in the database has an optional payment addr required bit set, then we'll
  1425  // still allow it to be paid by an incoming HTLC that doesn't include the MPP
  1426  // payload. This ensures we don't break payment for any invoices in the wild.
  1427  func TestSettleInvoicePaymentAddrRequiredOptionalGrace(t *testing.T) {
  1428  	t.Parallel()
  1429  
  1430  	ctx := newTestContext(t)
  1431  	defer ctx.cleanup()
  1432  
  1433  	allSubscriptions, err := ctx.registry.SubscribeNotifications(0, 0)
  1434  	require.Nil(t, err)
  1435  	defer allSubscriptions.Cancel()
  1436  
  1437  	// Subscribe to the not yet existing invoice.
  1438  	subscription, err := ctx.registry.SubscribeSingleInvoice(
  1439  		testInvoicePaymentHash,
  1440  	)
  1441  	require.NoError(t, err)
  1442  	defer subscription.Cancel()
  1443  
  1444  	require.Equal(
  1445  		t, subscription.invoiceRef.PayHash(), &testInvoicePaymentHash,
  1446  	)
  1447  
  1448  	// Add the invoice, which requires the MPP payload to always be
  1449  	// included due to its set of feature bits.
  1450  	addIdx, err := ctx.registry.AddInvoice(
  1451  		testPayAddrOptionalInvoice, testInvoicePaymentHash,
  1452  	)
  1453  	require.NoError(t, err)
  1454  	require.Equal(t, int(addIdx), 1)
  1455  
  1456  	// We expect the open state to be sent to the single invoice
  1457  	// subscriber.
  1458  	select {
  1459  	case update := <-subscription.Updates:
  1460  		if update.State != channeldb.ContractOpen {
  1461  			t.Fatalf("expected state ContractOpen, but got %v",
  1462  				update.State)
  1463  		}
  1464  	case <-time.After(testTimeout):
  1465  		t.Fatal("no update received")
  1466  	}
  1467  
  1468  	// We expect a new invoice notification to be sent out.
  1469  	select {
  1470  	case newInvoice := <-allSubscriptions.NewInvoices:
  1471  		if newInvoice.State != channeldb.ContractOpen {
  1472  			t.Fatalf("expected state ContractOpen, but got %v",
  1473  				newInvoice.State)
  1474  		}
  1475  	case <-time.After(testTimeout):
  1476  		t.Fatal("no update received")
  1477  	}
  1478  
  1479  	// We'll now attempt to settle the invoice as normal, this should work
  1480  	// no problem as we should allow these existing invoices to be settled.
  1481  	hodlChan := make(chan interface{}, 1)
  1482  	resolution, err := ctx.registry.NotifyExitHopHtlc(
  1483  		testInvoicePaymentHash, testInvoiceAmt,
  1484  		testHtlcExpiry, testCurrentHeight,
  1485  		getCircuitKey(10), hodlChan, testPayload,
  1486  	)
  1487  	require.NoError(t, err)
  1488  
  1489  	settleResolution, ok := resolution.(*HtlcSettleResolution)
  1490  	if !ok {
  1491  		t.Fatalf("expected settle resolution, got: %T",
  1492  			resolution)
  1493  	}
  1494  	require.Equal(t, settleResolution.Outcome, ResultSettled)
  1495  
  1496  	// We expect the settled state to be sent to the single invoice
  1497  	// subscriber.
  1498  	select {
  1499  	case update := <-subscription.Updates:
  1500  		if update.State != channeldb.ContractSettled {
  1501  			t.Fatalf("expected state ContractOpen, but got %v",
  1502  				update.State)
  1503  		}
  1504  		if update.AmtPaid != testInvoice.Terms.Value {
  1505  			t.Fatal("invoice AmtPaid incorrect")
  1506  		}
  1507  	case <-time.After(testTimeout):
  1508  		t.Fatal("no update received")
  1509  	}
  1510  
  1511  	// We expect a settled notification to be sent out.
  1512  	select {
  1513  	case settledInvoice := <-allSubscriptions.SettledInvoices:
  1514  		if settledInvoice.State != channeldb.ContractSettled {
  1515  			t.Fatalf("expected state ContractOpen, but got %v",
  1516  				settledInvoice.State)
  1517  		}
  1518  	case <-time.After(testTimeout):
  1519  		t.Fatal("no update received")
  1520  	}
  1521  }
  1522  
  1523  // TestAMPWithoutMPPPayload asserts that we correctly reject an AMP HTLC that
  1524  // does not include an MPP record.
  1525  func TestAMPWithoutMPPPayload(t *testing.T) {
  1526  	defer timeout()()
  1527  
  1528  	ctx := newTestContext(t)
  1529  	defer ctx.cleanup()
  1530  
  1531  	ctx.registry.cfg.AcceptAMP = true
  1532  
  1533  	const (
  1534  		shardAmt = lnwire.MilliAtom(10)
  1535  		expiry   = uint32(testCurrentHeight + 20)
  1536  	)
  1537  
  1538  	// Create payload with missing MPP field.
  1539  	payload := &mockPayload{
  1540  		amp: record.NewAMP([32]byte{}, [32]byte{}, 0),
  1541  	}
  1542  
  1543  	hodlChan := make(chan interface{}, 1)
  1544  	resolution, err := ctx.registry.NotifyExitHopHtlc(
  1545  		lntypes.Hash{}, shardAmt, expiry,
  1546  		testCurrentHeight, getCircuitKey(uint64(10)), hodlChan,
  1547  		payload,
  1548  	)
  1549  	require.NoError(t, err)
  1550  
  1551  	// We should receive the ResultAmpError failure.
  1552  	require.NotNil(t, resolution)
  1553  	checkFailResolution(t, resolution, ResultAmpError)
  1554  }
  1555  
  1556  // TestSpontaneousAmpPayment tests receiving a spontaneous AMP payment with both
  1557  // valid and invalid reconstructions.
  1558  func TestSpontaneousAmpPayment(t *testing.T) {
  1559  	tests := []struct {
  1560  		name               string
  1561  		ampEnabled         bool
  1562  		failReconstruction bool
  1563  		numShards          int
  1564  	}{
  1565  		{
  1566  			name:               "enabled valid one shard",
  1567  			ampEnabled:         true,
  1568  			failReconstruction: false,
  1569  			numShards:          1,
  1570  		},
  1571  		{
  1572  			name:               "enabled valid multiple shards",
  1573  			ampEnabled:         true,
  1574  			failReconstruction: false,
  1575  			numShards:          3,
  1576  		},
  1577  		{
  1578  			name:               "enabled invalid one shard",
  1579  			ampEnabled:         true,
  1580  			failReconstruction: true,
  1581  			numShards:          1,
  1582  		},
  1583  		{
  1584  			name:               "enabled invalid multiple shards",
  1585  			ampEnabled:         true,
  1586  			failReconstruction: true,
  1587  			numShards:          3,
  1588  		},
  1589  		{
  1590  			name:               "disabled valid multiple shards",
  1591  			ampEnabled:         false,
  1592  			failReconstruction: false,
  1593  			numShards:          3,
  1594  		},
  1595  	}
  1596  
  1597  	for _, test := range tests {
  1598  		test := test
  1599  		t.Run(test.name, func(t *testing.T) {
  1600  			testSpontaneousAmpPayment(
  1601  				t, test.ampEnabled, test.failReconstruction,
  1602  				test.numShards,
  1603  			)
  1604  		})
  1605  	}
  1606  }
  1607  
  1608  // testSpontaneousAmpPayment runs a specific spontaneous AMP test case.
  1609  func testSpontaneousAmpPayment(
  1610  	t *testing.T, ampEnabled, failReconstruction bool, numShards int) {
  1611  
  1612  	defer timeout()()
  1613  
  1614  	ctx := newTestContext(t)
  1615  	defer ctx.cleanup()
  1616  
  1617  	ctx.registry.cfg.AcceptAMP = ampEnabled
  1618  
  1619  	allSubscriptions, err := ctx.registry.SubscribeNotifications(0, 0)
  1620  	require.Nil(t, err)
  1621  	defer allSubscriptions.Cancel()
  1622  
  1623  	const (
  1624  		totalAmt = lnwire.MilliAtom(360)
  1625  		expiry   = uint32(testCurrentHeight + 20)
  1626  	)
  1627  
  1628  	var (
  1629  		shardAmt = totalAmt / lnwire.MilliAtom(numShards)
  1630  		payAddr  [32]byte
  1631  		setID    [32]byte
  1632  	)
  1633  	_, err = rand.Read(payAddr[:])
  1634  	require.NoError(t, err)
  1635  	_, err = rand.Read(setID[:])
  1636  	require.NoError(t, err)
  1637  
  1638  	var sharer amp.Sharer
  1639  	sharer, err = amp.NewSeedSharer()
  1640  	require.NoError(t, err)
  1641  
  1642  	// Asserts that a new invoice is published on the NewInvoices channel.
  1643  	checkOpenSubscription := func() {
  1644  		t.Helper()
  1645  		newInvoice := <-allSubscriptions.NewInvoices
  1646  		require.Equal(t, newInvoice.State, channeldb.ContractOpen)
  1647  	}
  1648  
  1649  	// Asserts that a settled invoice is published on the SettledInvoices
  1650  	// channel.
  1651  	checkSettleSubscription := func() {
  1652  		t.Helper()
  1653  		settledInvoice := <-allSubscriptions.SettledInvoices
  1654  
  1655  		// Since this is an AMP invoice, the invoice state never
  1656  		// changes, but the AMP state should show that the setID has
  1657  		// been settled.
  1658  		htlcState := settledInvoice.AMPState[setID].State
  1659  		require.Equal(t, htlcState, channeldb.HtlcStateSettled)
  1660  	}
  1661  
  1662  	// Asserts that no invoice is published on the SettledInvoices channel
  1663  	// w/in two seconds.
  1664  	checkNoSettleSubscription := func() {
  1665  		t.Helper()
  1666  		select {
  1667  		case <-allSubscriptions.SettledInvoices:
  1668  			t.Fatal("no settle ntfn expected")
  1669  		case <-time.After(2 * time.Second):
  1670  		}
  1671  	}
  1672  
  1673  	// Record the hodl channels of all HTLCs but the last one, which
  1674  	// received its resolution directly from NotifyExistHopHtlc.
  1675  	hodlChans := make(map[lntypes.Preimage]chan interface{})
  1676  	for i := 0; i < numShards; i++ {
  1677  		isFinalShard := i == numShards-1
  1678  
  1679  		hodlChan := make(chan interface{}, 1)
  1680  
  1681  		var child *amp.Child
  1682  		if !isFinalShard {
  1683  			var left amp.Sharer
  1684  			left, sharer, err = sharer.Split()
  1685  			require.NoError(t, err)
  1686  
  1687  			child = left.Child(uint32(i))
  1688  
  1689  			// Only store the first numShards-1 hodlChans.
  1690  			hodlChans[child.Preimage] = hodlChan
  1691  		} else {
  1692  			child = sharer.Child(uint32(i))
  1693  		}
  1694  
  1695  		// Send a blank share when the set should fail reconstruction,
  1696  		// otherwise send the derived share.
  1697  		var share [32]byte
  1698  		if !failReconstruction {
  1699  			share = child.Share
  1700  		}
  1701  
  1702  		payload := &mockPayload{
  1703  			mpp: record.NewMPP(totalAmt, payAddr),
  1704  			amp: record.NewAMP(share, setID, uint32(i)),
  1705  		}
  1706  
  1707  		resolution, err := ctx.registry.NotifyExitHopHtlc(
  1708  			child.Hash, shardAmt, expiry,
  1709  			testCurrentHeight, getCircuitKey(uint64(i)), hodlChan,
  1710  			payload,
  1711  		)
  1712  		require.NoError(t, err)
  1713  
  1714  		// When keysend is disabled all HTLC should fail with invoice
  1715  		// not found, since one is not inserted before executing
  1716  		// UpdateInvoice.
  1717  		if !ampEnabled {
  1718  			require.NotNil(t, resolution)
  1719  			checkFailResolution(t, resolution, ResultInvoiceNotFound)
  1720  			continue
  1721  		}
  1722  
  1723  		// Check that resolutions are properly formed.
  1724  		if !isFinalShard {
  1725  			// Non-final shares should always return a nil
  1726  			// resolution, theirs will be delivered via the
  1727  			// hodlChan.
  1728  			require.Nil(t, resolution)
  1729  		} else {
  1730  			// The final share should receive a non-nil resolution.
  1731  			// Also assert that it is the proper type based on the
  1732  			// test case.
  1733  			require.NotNil(t, resolution)
  1734  			if failReconstruction {
  1735  				checkFailResolution(t, resolution, ResultAmpReconstruction)
  1736  			} else {
  1737  				checkSettleResolution(t, resolution, child.Preimage)
  1738  			}
  1739  		}
  1740  
  1741  		// Assert the behavior of the Open and Settle notifications.
  1742  		// There should always be an open (keysend is enabled) followed
  1743  		// by settle for valid AMP payments.
  1744  		//
  1745  		// NOTE: The cases are split in separate if conditions, rather
  1746  		// than else-if, to properly handle the case when there is only
  1747  		// one shard.
  1748  		if i == 0 {
  1749  			checkOpenSubscription()
  1750  		}
  1751  		if isFinalShard {
  1752  			if failReconstruction {
  1753  				checkNoSettleSubscription()
  1754  			} else {
  1755  				checkSettleSubscription()
  1756  			}
  1757  		}
  1758  	}
  1759  
  1760  	// No need to check the hodl chans when keysend is not enabled.
  1761  	if !ampEnabled {
  1762  		return
  1763  	}
  1764  
  1765  	// For the non-final hodl chans, assert that they receive the expected
  1766  	// failure or preimage.
  1767  	for preimage, hodlChan := range hodlChans {
  1768  		resolution, ok := (<-hodlChan).(HtlcResolution)
  1769  		require.True(t, ok)
  1770  		require.NotNil(t, resolution)
  1771  		if failReconstruction {
  1772  			checkFailResolution(t, resolution, ResultAmpReconstruction)
  1773  		} else {
  1774  			checkSettleResolution(t, resolution, preimage)
  1775  		}
  1776  	}
  1777  }