invoices: add checkSettleResolution and checkFailResolution

Also refactor existing unit tests to use them.
This commit is contained in:
Conner Fromknecht 2021-03-24 19:48:59 -07:00
parent 7e2f5a184b
commit 3fb70dd936
No known key found for this signature in database
GPG Key ID: E7D737B67FA592C7
2 changed files with 87 additions and 142 deletions

@ -75,19 +75,11 @@ func TestSettleInvoice(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
failResolution, ok := resolution.(*HtlcFailResolution) require.NotNil(t, resolution)
if !ok { failResolution := checkFailResolution(
t.Fatalf("expected fail resolution, got: %T", t, resolution, ResultExpiryTooSoon,
resolution) )
} require.Equal(t, testCurrentHeight, failResolution.AcceptHeight)
if failResolution.AcceptHeight != testCurrentHeight {
t.Fatalf("expected acceptHeight %v, but got %v",
testCurrentHeight, failResolution.AcceptHeight)
}
if failResolution.Outcome != ResultExpiryTooSoon {
t.Fatalf("expected expiry too soon, got: %v",
failResolution.Outcome)
}
// Settle invoice with a slightly higher amount. // Settle invoice with a slightly higher amount.
amtPaid := lnwire.MilliSatoshi(100500) amtPaid := lnwire.MilliSatoshi(100500)
@ -99,15 +91,11 @@ func TestSettleInvoice(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
settleResolution, ok := resolution.(*HtlcSettleResolution) require.NotNil(t, resolution)
if !ok { settleResolution := checkSettleResolution(
t.Fatalf("expected settle resolution, got: %T", t, resolution, testInvoicePreimage,
resolution) )
} require.Equal(t, ResultSettled, settleResolution.Outcome)
if settleResolution.Outcome != ResultSettled {
t.Fatalf("expected settled, got: %v",
settleResolution.Outcome)
}
// We expect the settled state to be sent to the single invoice // We expect the settled state to be sent to the single invoice
// subscriber. // subscriber.
@ -144,15 +132,11 @@ func TestSettleInvoice(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("unexpected NotifyExitHopHtlc error: %v", err) t.Fatalf("unexpected NotifyExitHopHtlc error: %v", err)
} }
settleResolution, ok = resolution.(*HtlcSettleResolution) require.NotNil(t, resolution)
if !ok { settleResolution = checkSettleResolution(
t.Fatalf("expected settle resolution, got: %T", t, resolution, testInvoicePreimage,
resolution) )
} require.Equal(t, ResultReplayToSettled, settleResolution.Outcome)
if settleResolution.Outcome != ResultReplayToSettled {
t.Fatalf("expected replay settled, got: %v",
settleResolution.Outcome)
}
// Try to settle again with a new higher-valued htlc. This payment // Try to settle again with a new higher-valued htlc. This payment
// should also be accepted, to prevent any change in behaviour for a // should also be accepted, to prevent any change in behaviour for a
@ -164,15 +148,11 @@ func TestSettleInvoice(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("unexpected NotifyExitHopHtlc error: %v", err) t.Fatalf("unexpected NotifyExitHopHtlc error: %v", err)
} }
settleResolution, ok = resolution.(*HtlcSettleResolution) require.NotNil(t, resolution)
if !ok { settleResolution = checkSettleResolution(
t.Fatalf("expected settle resolution, got: %T", t, resolution, testInvoicePreimage,
resolution) )
} require.Equal(t, ResultDuplicateToSettled, settleResolution.Outcome)
if settleResolution.Outcome != ResultDuplicateToSettled {
t.Fatalf("expected duplicate settled, got: %v",
settleResolution.Outcome)
}
// Try to settle again with a lower amount. This should fail just as it // Try to settle again with a lower amount. This should fail just as it
// would have failed if it were the first payment. // would have failed if it were the first payment.
@ -183,15 +163,8 @@ func TestSettleInvoice(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("unexpected NotifyExitHopHtlc error: %v", err) t.Fatalf("unexpected NotifyExitHopHtlc error: %v", err)
} }
failResolution, ok = resolution.(*HtlcFailResolution) require.NotNil(t, resolution)
if !ok { checkFailResolution(t, resolution, ResultAmountTooLow)
t.Fatalf("expected fail resolution, got: %T",
resolution)
}
if failResolution.Outcome != ResultAmountTooLow {
t.Fatalf("expected amount too low, got: %v",
failResolution.Outcome)
}
// Check that settled amount is equal to the sum of values of the htlcs // Check that settled amount is equal to the sum of values of the htlcs
// 0 and 1. // 0 and 1.
@ -329,27 +302,23 @@ func testCancelInvoice(t *testing.T, gc bool) {
if err != nil { if err != nil {
t.Fatal("expected settlement of a canceled invoice to succeed") t.Fatal("expected settlement of a canceled invoice to succeed")
} }
failResolution, ok := resolution.(*HtlcFailResolution) require.NotNil(t, resolution)
if !ok {
t.Fatalf("expected fail resolution, got: %T",
resolution)
}
if failResolution.AcceptHeight != testCurrentHeight {
t.Fatalf("expected acceptHeight %v, but got %v",
testCurrentHeight, failResolution.AcceptHeight)
}
// If the invoice has been deleted (or not present) then we expect the // If the invoice has been deleted (or not present) then we expect the
// outcome to be ResultInvoiceNotFound instead of when the invoice is // outcome to be ResultInvoiceNotFound instead of when the invoice is
// in our database in which case we expect ResultInvoiceAlreadyCanceled. // in our database in which case we expect ResultInvoiceAlreadyCanceled.
var failResolution *HtlcFailResolution
if gc { if gc {
require.Equal(t, failResolution.Outcome, ResultInvoiceNotFound) failResolution = checkFailResolution(
t, resolution, ResultInvoiceNotFound,
)
} else { } else {
require.Equal(t, failResolution = checkFailResolution(
failResolution.Outcome, t, resolution, ResultInvoiceAlreadyCanceled,
ResultInvoiceAlreadyCanceled,
) )
} }
require.Equal(t, testCurrentHeight, failResolution.AcceptHeight)
} }
// TestCancelInvoice tests cancelation of an invoice and related notifications. // TestCancelInvoice tests cancelation of an invoice and related notifications.
@ -474,15 +443,8 @@ func TestSettleHoldInvoice(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("expected settle to succeed but got %v", err) t.Fatalf("expected settle to succeed but got %v", err)
} }
failResolution, ok := resolution.(*HtlcFailResolution) require.NotNil(t, resolution)
if !ok { checkFailResolution(t, resolution, ResultExpiryTooSoon)
t.Fatalf("expected fail resolution, got: %T",
resolution)
}
if failResolution.Outcome != ResultExpiryTooSoon {
t.Fatalf("expected expiry too soon, got: %v",
failResolution.Outcome)
}
// We expect the accepted state to be sent to the single invoice // We expect the accepted state to be sent to the single invoice
// subscriber. For all invoice subscribers, we don't expect an update. // subscriber. For all invoice subscribers, we don't expect an update.
@ -503,22 +465,12 @@ func TestSettleHoldInvoice(t *testing.T) {
} }
htlcResolution := (<-hodlChan).(HtlcResolution) htlcResolution := (<-hodlChan).(HtlcResolution)
settleResolution, ok := htlcResolution.(*HtlcSettleResolution) require.NotNil(t, htlcResolution)
if !ok { settleResolution := checkSettleResolution(
t.Fatalf("expected settle resolution, got: %T", t, htlcResolution, testInvoicePreimage,
htlcResolution) )
} require.Equal(t, testCurrentHeight, settleResolution.AcceptHeight)
if settleResolution.Preimage != testInvoicePreimage { require.Equal(t, ResultSettled, settleResolution.Outcome)
t.Fatal("unexpected preimage in hodl resolution")
}
if settleResolution.AcceptHeight != testCurrentHeight {
t.Fatalf("expected acceptHeight %v, but got %v",
testCurrentHeight, settleResolution.AcceptHeight)
}
if settleResolution.Outcome != ResultSettled {
t.Fatalf("expected result settled, got: %v",
settleResolution.Outcome)
}
// We expect a settled notification to be sent out for both all and // We expect a settled notification to be sent out for both all and
// single invoice subscribers. // single invoice subscribers.
@ -604,11 +556,8 @@ func TestCancelHoldInvoice(t *testing.T) {
} }
htlcResolution := (<-hodlChan).(HtlcResolution) htlcResolution := (<-hodlChan).(HtlcResolution)
_, ok := htlcResolution.(*HtlcFailResolution) require.NotNil(t, htlcResolution)
if !ok { checkFailResolution(t, htlcResolution, ResultCanceled)
t.Fatalf("expected fail resolution, got: %T",
htlcResolution)
}
// Offering the same htlc again at a higher height should still result // Offering the same htlc again at a higher height should still result
// in a rejection. The accept height is expected to be the original // in a rejection. The accept height is expected to be the original
@ -620,19 +569,11 @@ func TestCancelHoldInvoice(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("expected settle to succeed but got %v", err) t.Fatalf("expected settle to succeed but got %v", err)
} }
failResolution, ok := resolution.(*HtlcFailResolution) require.NotNil(t, resolution)
if !ok { failResolution := checkFailResolution(
t.Fatalf("expected fail resolution, got: %T", t, resolution, ResultReplayToCanceled,
resolution) )
} require.Equal(t, testCurrentHeight, failResolution.AcceptHeight)
if failResolution.AcceptHeight != testCurrentHeight {
t.Fatalf("expected acceptHeight %v, but got %v",
testCurrentHeight, failResolution.AcceptHeight)
}
if failResolution.Outcome != ResultReplayToCanceled {
t.Fatalf("expected replay to canceled, got %v",
failResolution.Outcome)
}
} }
// TestUnknownInvoice tests that invoice registry returns an error when the // TestUnknownInvoice tests that invoice registry returns an error when the
@ -655,15 +596,8 @@ func TestUnknownInvoice(t *testing.T) {
if err != nil { if err != nil {
t.Fatal("unexpected error") t.Fatal("unexpected error")
} }
failResolution, ok := resolution.(*HtlcFailResolution) require.NotNil(t, resolution)
if !ok { checkFailResolution(t, resolution, ResultInvoiceNotFound)
t.Fatalf("expected fail resolution, got: %T",
resolution)
}
if failResolution.Outcome != ResultInvoiceNotFound {
t.Fatalf("expected ResultInvoiceNotFound, got: %v",
failResolution.Outcome)
}
} }
// TestKeySend tests receiving a spontaneous payment with and without keysend // TestKeySend tests receiving a spontaneous payment with and without keysend
@ -715,18 +649,12 @@ func testKeySend(t *testing.T, keySendEnabled bool) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
failResolution, ok := resolution.(*HtlcFailResolution) require.NotNil(t, resolution)
if !ok {
t.Fatalf("expected fail resolution, got: %T",
resolution)
}
switch { if !keySendEnabled {
case !keySendEnabled && failResolution.Outcome != ResultInvoiceNotFound: checkFailResolution(t, resolution, ResultInvoiceNotFound)
t.Fatal("expected invoice not found outcome") } else {
checkFailResolution(t, resolution, ResultKeySendError)
case keySendEnabled && failResolution.Outcome != ResultKeySendError:
t.Fatal("expected keysend error")
} }
// Try to settle invoice with a valid keysend htlc. // Try to settle invoice with a valid keysend htlc.
@ -746,23 +674,10 @@ func testKeySend(t *testing.T, keySendEnabled bool) {
// Expect a cancel resolution if keysend is disabled. // Expect a cancel resolution if keysend is disabled.
if !keySendEnabled { if !keySendEnabled {
failResolution, ok = resolution.(*HtlcFailResolution) checkFailResolution(t, resolution, ResultInvoiceNotFound)
if !ok {
t.Fatalf("expected fail resolution, got: %T",
resolution)
}
if failResolution.Outcome != ResultInvoiceNotFound {
t.Fatal("expected keysend payment not to be accepted")
}
return return
} }
checkResolution := func(res HtlcResolution, pimg lntypes.Preimage) {
// Otherwise we expect no error and a settle res for the htlc.
settleResolution, ok := res.(*HtlcSettleResolution)
require.True(t, ok)
require.Equal(t, settleResolution.Preimage, pimg)
}
checkSubscription := func() { checkSubscription := func() {
// We expect a new invoice notification to be sent out. // We expect a new invoice notification to be sent out.
newInvoice := <-allSubscriptions.NewInvoices newInvoice := <-allSubscriptions.NewInvoices
@ -773,7 +688,7 @@ func testKeySend(t *testing.T, keySendEnabled bool) {
require.Equal(t, settledInvoice.State, channeldb.ContractSettled) require.Equal(t, settledInvoice.State, channeldb.ContractSettled)
} }
checkResolution(resolution, preimage) checkSettleResolution(t, resolution, preimage)
checkSubscription() checkSubscription()
// Replay the same keysend payment. We expect an identical resolution, // Replay the same keysend payment. We expect an identical resolution,
@ -783,7 +698,7 @@ func testKeySend(t *testing.T, keySendEnabled bool) {
testCurrentHeight, getCircuitKey(10), hodlChan, keySendPayload, testCurrentHeight, getCircuitKey(10), hodlChan, keySendPayload,
) )
require.Nil(t, err) require.Nil(t, err)
checkResolution(resolution, preimage) checkSettleResolution(t, resolution, preimage)
select { select {
case <-allSubscriptions.NewInvoices: case <-allSubscriptions.NewInvoices:
@ -808,7 +723,7 @@ func testKeySend(t *testing.T, keySendEnabled bool) {
) )
require.Nil(t, err) require.Nil(t, err)
checkResolution(resolution, preimage2) checkSettleResolution(t, resolution, preimage2)
checkSubscription() checkSubscription()
} }

@ -19,6 +19,7 @@ import (
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/record" "github.com/lightningnetwork/lnd/record"
"github.com/lightningnetwork/lnd/zpay32" "github.com/lightningnetwork/lnd/zpay32"
"github.com/stretchr/testify/require"
) )
type mockPayload struct { type mockPayload struct {
@ -331,3 +332,32 @@ func generateInvoiceExpiryTestData(
return testData return testData
} }
// checkSettleResolution asserts the resolution is a settle with the correct
// preimage. If successful, the HtlcSettleResolution is returned in case further
// checks are desired.
func checkSettleResolution(t *testing.T, res HtlcResolution,
expPreimage lntypes.Preimage) *HtlcSettleResolution {
t.Helper()
settleResolution, ok := res.(*HtlcSettleResolution)
require.True(t, ok)
require.Equal(t, expPreimage, settleResolution.Preimage)
return settleResolution
}
// checkFailResolution asserts the resolution is a fail with the correct reason.
// If successful, the HtlcFailResolutionis returned in case further checks are
// desired.
func checkFailResolution(t *testing.T, res HtlcResolution,
expOutcome FailResolutionResult) *HtlcFailResolution {
t.Helper()
failResolution, ok := res.(*HtlcFailResolution)
require.True(t, ok)
require.Equal(t, expOutcome, failResolution.Outcome)
return failResolution
}