invoices: refactor test helpers
This commit moves test helpers to their on file, while also adding helper to create an invoice with a valid payment request.
This commit is contained in:
parent
27430f8bc9
commit
88e01fa1fa
@ -1,117 +1,14 @@
|
|||||||
package invoices
|
package invoices
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/record"
|
"github.com/lightningnetwork/lnd/record"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
testTimeout = 5 * time.Second
|
|
||||||
|
|
||||||
testTime = time.Date(2018, time.February, 2, 14, 0, 0, 0, time.UTC)
|
|
||||||
|
|
||||||
preimage = lntypes.Preimage{
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
hash = preimage.Hash()
|
|
||||||
|
|
||||||
testHtlcExpiry = uint32(5)
|
|
||||||
|
|
||||||
testInvoiceCltvDelta = uint32(4)
|
|
||||||
|
|
||||||
testFinalCltvRejectDelta = int32(4)
|
|
||||||
|
|
||||||
testCurrentHeight = int32(1)
|
|
||||||
|
|
||||||
testFeatures = lnwire.NewFeatureVector(
|
|
||||||
nil, lnwire.Features,
|
|
||||||
)
|
|
||||||
|
|
||||||
testPayload = &mockPayload{}
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
testInvoiceAmt = lnwire.MilliSatoshi(100000)
|
|
||||||
testInvoice = &channeldb.Invoice{
|
|
||||||
Terms: channeldb.ContractTerm{
|
|
||||||
PaymentPreimage: preimage,
|
|
||||||
Value: lnwire.MilliSatoshi(100000),
|
|
||||||
Features: testFeatures,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
testHodlInvoice = &channeldb.Invoice{
|
|
||||||
Terms: channeldb.ContractTerm{
|
|
||||||
PaymentPreimage: channeldb.UnknownPreimage,
|
|
||||||
Value: testInvoiceAmt,
|
|
||||||
Features: testFeatures,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
type testContext struct {
|
|
||||||
registry *InvoiceRegistry
|
|
||||||
clock *testClock
|
|
||||||
|
|
||||||
cleanup func()
|
|
||||||
t *testing.T
|
|
||||||
}
|
|
||||||
|
|
||||||
func newTestContext(t *testing.T) *testContext {
|
|
||||||
clock := newTestClock(testTime)
|
|
||||||
|
|
||||||
cdb, cleanup, err := newDB()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
cdb.Now = clock.now
|
|
||||||
|
|
||||||
// Instantiate and start the invoice ctx.registry.
|
|
||||||
cfg := RegistryConfig{
|
|
||||||
FinalCltvRejectDelta: testFinalCltvRejectDelta,
|
|
||||||
HtlcHoldDuration: 30 * time.Second,
|
|
||||||
Now: clock.now,
|
|
||||||
TickAfter: clock.tickAfter,
|
|
||||||
}
|
|
||||||
registry := NewRegistry(cdb, &cfg)
|
|
||||||
|
|
||||||
err = registry.Start()
|
|
||||||
if err != nil {
|
|
||||||
cleanup()
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := testContext{
|
|
||||||
registry: registry,
|
|
||||||
clock: clock,
|
|
||||||
t: t,
|
|
||||||
cleanup: func() {
|
|
||||||
registry.Stop()
|
|
||||||
cleanup()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
return &ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
func getCircuitKey(htlcID uint64) channeldb.CircuitKey {
|
|
||||||
return channeldb.CircuitKey{
|
|
||||||
ChanID: lnwire.ShortChannelID{
|
|
||||||
BlockHeight: 1, TxIndex: 2, TxPosition: 3,
|
|
||||||
},
|
|
||||||
HtlcID: htlcID,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestSettleInvoice tests settling of an invoice and related notifications.
|
// TestSettleInvoice tests settling of an invoice and related notifications.
|
||||||
func TestSettleInvoice(t *testing.T) {
|
func TestSettleInvoice(t *testing.T) {
|
||||||
ctx := newTestContext(t)
|
ctx := newTestContext(t)
|
||||||
@ -121,18 +18,18 @@ func TestSettleInvoice(t *testing.T) {
|
|||||||
defer allSubscriptions.Cancel()
|
defer allSubscriptions.Cancel()
|
||||||
|
|
||||||
// Subscribe to the not yet existing invoice.
|
// Subscribe to the not yet existing invoice.
|
||||||
subscription, err := ctx.registry.SubscribeSingleInvoice(hash)
|
subscription, err := ctx.registry.SubscribeSingleInvoice(testInvoicePaymentHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer subscription.Cancel()
|
defer subscription.Cancel()
|
||||||
|
|
||||||
if subscription.hash != hash {
|
if subscription.hash != testInvoicePaymentHash {
|
||||||
t.Fatalf("expected subscription for provided hash")
|
t.Fatalf("expected subscription for provided hash")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the invoice.
|
// Add the invoice.
|
||||||
addIdx, err := ctx.registry.AddInvoice(testInvoice, hash)
|
addIdx, err := ctx.registry.AddInvoice(testInvoice, testInvoicePaymentHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -168,7 +65,7 @@ func TestSettleInvoice(t *testing.T) {
|
|||||||
|
|
||||||
// Try to settle invoice with an htlc that expires too soon.
|
// Try to settle invoice with an htlc that expires too soon.
|
||||||
event, err := ctx.registry.NotifyExitHopHtlc(
|
event, err := ctx.registry.NotifyExitHopHtlc(
|
||||||
hash, testInvoice.Terms.Value,
|
testInvoicePaymentHash, testInvoice.Terms.Value,
|
||||||
uint32(testCurrentHeight)+testInvoiceCltvDelta-1,
|
uint32(testCurrentHeight)+testInvoiceCltvDelta-1,
|
||||||
testCurrentHeight, getCircuitKey(10), hodlChan, testPayload,
|
testCurrentHeight, getCircuitKey(10), hodlChan, testPayload,
|
||||||
)
|
)
|
||||||
@ -186,7 +83,7 @@ func TestSettleInvoice(t *testing.T) {
|
|||||||
// Settle invoice with a slightly higher amount.
|
// Settle invoice with a slightly higher amount.
|
||||||
amtPaid := lnwire.MilliSatoshi(100500)
|
amtPaid := lnwire.MilliSatoshi(100500)
|
||||||
_, err = ctx.registry.NotifyExitHopHtlc(
|
_, err = ctx.registry.NotifyExitHopHtlc(
|
||||||
hash, amtPaid, testHtlcExpiry, testCurrentHeight,
|
testInvoicePaymentHash, amtPaid, testHtlcExpiry, testCurrentHeight,
|
||||||
getCircuitKey(0), hodlChan, testPayload,
|
getCircuitKey(0), hodlChan, testPayload,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -222,7 +119,7 @@ func TestSettleInvoice(t *testing.T) {
|
|||||||
// Try to settle again with the same htlc id. We need this idempotent
|
// Try to settle again with the same htlc id. We need this idempotent
|
||||||
// behaviour after a restart.
|
// behaviour after a restart.
|
||||||
event, err = ctx.registry.NotifyExitHopHtlc(
|
event, err = ctx.registry.NotifyExitHopHtlc(
|
||||||
hash, amtPaid, testHtlcExpiry, testCurrentHeight,
|
testInvoicePaymentHash, amtPaid, testHtlcExpiry, testCurrentHeight,
|
||||||
getCircuitKey(0), hodlChan, testPayload,
|
getCircuitKey(0), hodlChan, testPayload,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -236,7 +133,7 @@ func TestSettleInvoice(t *testing.T) {
|
|||||||
// should also be accepted, to prevent any change in behaviour for a
|
// should also be accepted, to prevent any change in behaviour for a
|
||||||
// paid invoice that may open up a probe vector.
|
// paid invoice that may open up a probe vector.
|
||||||
event, err = ctx.registry.NotifyExitHopHtlc(
|
event, err = ctx.registry.NotifyExitHopHtlc(
|
||||||
hash, amtPaid+600, testHtlcExpiry, testCurrentHeight,
|
testInvoicePaymentHash, amtPaid+600, testHtlcExpiry, testCurrentHeight,
|
||||||
getCircuitKey(1), hodlChan, testPayload,
|
getCircuitKey(1), hodlChan, testPayload,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -249,7 +146,7 @@ func TestSettleInvoice(t *testing.T) {
|
|||||||
// 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.
|
||||||
event, err = ctx.registry.NotifyExitHopHtlc(
|
event, err = ctx.registry.NotifyExitHopHtlc(
|
||||||
hash, amtPaid-600, testHtlcExpiry, testCurrentHeight,
|
testInvoicePaymentHash, amtPaid-600, testHtlcExpiry, testCurrentHeight,
|
||||||
getCircuitKey(2), hodlChan, testPayload,
|
getCircuitKey(2), hodlChan, testPayload,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -261,7 +158,7 @@ func TestSettleInvoice(t *testing.T) {
|
|||||||
|
|
||||||
// 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.
|
||||||
inv, err := ctx.registry.LookupInvoice(hash)
|
inv, err := ctx.registry.LookupInvoice(testInvoicePaymentHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -270,7 +167,7 @@ func TestSettleInvoice(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Try to cancel.
|
// Try to cancel.
|
||||||
err = ctx.registry.CancelInvoice(hash)
|
err = ctx.registry.CancelInvoice(testInvoicePaymentHash)
|
||||||
if err != channeldb.ErrInvoiceAlreadySettled {
|
if err != channeldb.ErrInvoiceAlreadySettled {
|
||||||
t.Fatal("expected cancelation of a settled invoice to fail")
|
t.Fatal("expected cancelation of a settled invoice to fail")
|
||||||
}
|
}
|
||||||
@ -292,25 +189,25 @@ func TestCancelInvoice(t *testing.T) {
|
|||||||
defer allSubscriptions.Cancel()
|
defer allSubscriptions.Cancel()
|
||||||
|
|
||||||
// Try to cancel the not yet existing invoice. This should fail.
|
// Try to cancel the not yet existing invoice. This should fail.
|
||||||
err := ctx.registry.CancelInvoice(hash)
|
err := ctx.registry.CancelInvoice(testInvoicePaymentHash)
|
||||||
if err != channeldb.ErrInvoiceNotFound {
|
if err != channeldb.ErrInvoiceNotFound {
|
||||||
t.Fatalf("expected ErrInvoiceNotFound, but got %v", err)
|
t.Fatalf("expected ErrInvoiceNotFound, but got %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subscribe to the not yet existing invoice.
|
// Subscribe to the not yet existing invoice.
|
||||||
subscription, err := ctx.registry.SubscribeSingleInvoice(hash)
|
subscription, err := ctx.registry.SubscribeSingleInvoice(testInvoicePaymentHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer subscription.Cancel()
|
defer subscription.Cancel()
|
||||||
|
|
||||||
if subscription.hash != hash {
|
if subscription.hash != testInvoicePaymentHash {
|
||||||
t.Fatalf("expected subscription for provided hash")
|
t.Fatalf("expected subscription for provided hash")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the invoice.
|
// Add the invoice.
|
||||||
amt := lnwire.MilliSatoshi(100000)
|
amt := lnwire.MilliSatoshi(100000)
|
||||||
_, err = ctx.registry.AddInvoice(testInvoice, hash)
|
_, err = ctx.registry.AddInvoice(testInvoice, testInvoicePaymentHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -342,7 +239,7 @@ func TestCancelInvoice(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Cancel invoice.
|
// Cancel invoice.
|
||||||
err = ctx.registry.CancelInvoice(hash)
|
err = ctx.registry.CancelInvoice(testInvoicePaymentHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -365,7 +262,7 @@ func TestCancelInvoice(t *testing.T) {
|
|||||||
// subscribers (backwards compatibility).
|
// subscribers (backwards compatibility).
|
||||||
|
|
||||||
// Try to cancel again.
|
// Try to cancel again.
|
||||||
err = ctx.registry.CancelInvoice(hash)
|
err = ctx.registry.CancelInvoice(testInvoicePaymentHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("expected cancelation of a canceled invoice to succeed")
|
t.Fatal("expected cancelation of a canceled invoice to succeed")
|
||||||
}
|
}
|
||||||
@ -374,7 +271,7 @@ func TestCancelInvoice(t *testing.T) {
|
|||||||
// result in a cancel event.
|
// result in a cancel event.
|
||||||
hodlChan := make(chan interface{})
|
hodlChan := make(chan interface{})
|
||||||
event, err := ctx.registry.NotifyExitHopHtlc(
|
event, err := ctx.registry.NotifyExitHopHtlc(
|
||||||
hash, amt, testHtlcExpiry, testCurrentHeight,
|
testInvoicePaymentHash, amt, testHtlcExpiry, testCurrentHeight,
|
||||||
getCircuitKey(0), hodlChan, testPayload,
|
getCircuitKey(0), hodlChan, testPayload,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -393,9 +290,9 @@ func TestCancelInvoice(t *testing.T) {
|
|||||||
// TestSettleHoldInvoice tests settling of a hold invoice and related
|
// TestSettleHoldInvoice tests settling of a hold invoice and related
|
||||||
// notifications.
|
// notifications.
|
||||||
func TestSettleHoldInvoice(t *testing.T) {
|
func TestSettleHoldInvoice(t *testing.T) {
|
||||||
defer timeout(t)()
|
defer timeout()()
|
||||||
|
|
||||||
cdb, cleanup, err := newDB()
|
cdb, cleanup, err := newTestChannelDB()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -417,18 +314,18 @@ func TestSettleHoldInvoice(t *testing.T) {
|
|||||||
defer allSubscriptions.Cancel()
|
defer allSubscriptions.Cancel()
|
||||||
|
|
||||||
// Subscribe to the not yet existing invoice.
|
// Subscribe to the not yet existing invoice.
|
||||||
subscription, err := registry.SubscribeSingleInvoice(hash)
|
subscription, err := registry.SubscribeSingleInvoice(testInvoicePaymentHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer subscription.Cancel()
|
defer subscription.Cancel()
|
||||||
|
|
||||||
if subscription.hash != hash {
|
if subscription.hash != testInvoicePaymentHash {
|
||||||
t.Fatalf("expected subscription for provided hash")
|
t.Fatalf("expected subscription for provided hash")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the invoice.
|
// Add the invoice.
|
||||||
_, err = registry.AddInvoice(testHodlInvoice, hash)
|
_, err = registry.AddInvoice(testHodlInvoice, testInvoicePaymentHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -455,7 +352,7 @@ func TestSettleHoldInvoice(t *testing.T) {
|
|||||||
// NotifyExitHopHtlc without a preimage present in the invoice registry
|
// NotifyExitHopHtlc without a preimage present in the invoice registry
|
||||||
// should be possible.
|
// should be possible.
|
||||||
event, err := registry.NotifyExitHopHtlc(
|
event, err := registry.NotifyExitHopHtlc(
|
||||||
hash, amtPaid, testHtlcExpiry, testCurrentHeight,
|
testInvoicePaymentHash, amtPaid, testHtlcExpiry, testCurrentHeight,
|
||||||
getCircuitKey(0), hodlChan, testPayload,
|
getCircuitKey(0), hodlChan, testPayload,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -467,7 +364,7 @@ func TestSettleHoldInvoice(t *testing.T) {
|
|||||||
|
|
||||||
// Test idempotency.
|
// Test idempotency.
|
||||||
event, err = registry.NotifyExitHopHtlc(
|
event, err = registry.NotifyExitHopHtlc(
|
||||||
hash, amtPaid, testHtlcExpiry, testCurrentHeight,
|
testInvoicePaymentHash, amtPaid, testHtlcExpiry, testCurrentHeight,
|
||||||
getCircuitKey(0), hodlChan, testPayload,
|
getCircuitKey(0), hodlChan, testPayload,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -480,7 +377,7 @@ func TestSettleHoldInvoice(t *testing.T) {
|
|||||||
// Test replay at a higher height. We expect the same result because it
|
// Test replay at a higher height. We expect the same result because it
|
||||||
// is a replay.
|
// is a replay.
|
||||||
event, err = registry.NotifyExitHopHtlc(
|
event, err = registry.NotifyExitHopHtlc(
|
||||||
hash, amtPaid, testHtlcExpiry, testCurrentHeight+10,
|
testInvoicePaymentHash, amtPaid, testHtlcExpiry, testCurrentHeight+10,
|
||||||
getCircuitKey(0), hodlChan, testPayload,
|
getCircuitKey(0), hodlChan, testPayload,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -493,7 +390,7 @@ func TestSettleHoldInvoice(t *testing.T) {
|
|||||||
// Test a new htlc coming in that doesn't meet the final cltv delta
|
// Test a new htlc coming in that doesn't meet the final cltv delta
|
||||||
// requirement. It should be rejected.
|
// requirement. It should be rejected.
|
||||||
event, err = registry.NotifyExitHopHtlc(
|
event, err = registry.NotifyExitHopHtlc(
|
||||||
hash, amtPaid, 1, testCurrentHeight,
|
testInvoicePaymentHash, amtPaid, 1, testCurrentHeight,
|
||||||
getCircuitKey(1), hodlChan, testPayload,
|
getCircuitKey(1), hodlChan, testPayload,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -516,13 +413,13 @@ func TestSettleHoldInvoice(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Settling with preimage should succeed.
|
// Settling with preimage should succeed.
|
||||||
err = registry.SettleHodlInvoice(preimage)
|
err = registry.SettleHodlInvoice(testInvoicePreimage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("expected set preimage to succeed")
|
t.Fatal("expected set preimage to succeed")
|
||||||
}
|
}
|
||||||
|
|
||||||
hodlEvent := (<-hodlChan).(HodlEvent)
|
hodlEvent := (<-hodlChan).(HodlEvent)
|
||||||
if *hodlEvent.Preimage != preimage {
|
if *hodlEvent.Preimage != testInvoicePreimage {
|
||||||
t.Fatal("unexpected preimage in hodl event")
|
t.Fatal("unexpected preimage in hodl event")
|
||||||
}
|
}
|
||||||
if hodlEvent.AcceptHeight != testCurrentHeight {
|
if hodlEvent.AcceptHeight != testCurrentHeight {
|
||||||
@ -549,13 +446,13 @@ func TestSettleHoldInvoice(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Idempotency.
|
// Idempotency.
|
||||||
err = registry.SettleHodlInvoice(preimage)
|
err = registry.SettleHodlInvoice(testInvoicePreimage)
|
||||||
if err != channeldb.ErrInvoiceAlreadySettled {
|
if err != channeldb.ErrInvoiceAlreadySettled {
|
||||||
t.Fatalf("expected ErrInvoiceAlreadySettled but got %v", err)
|
t.Fatalf("expected ErrInvoiceAlreadySettled but got %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to cancel.
|
// Try to cancel.
|
||||||
err = registry.CancelInvoice(hash)
|
err = registry.CancelInvoice(testInvoicePaymentHash)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("expected cancelation of a settled invoice to fail")
|
t.Fatal("expected cancelation of a settled invoice to fail")
|
||||||
}
|
}
|
||||||
@ -564,9 +461,9 @@ func TestSettleHoldInvoice(t *testing.T) {
|
|||||||
// TestCancelHoldInvoice tests canceling of a hold invoice and related
|
// TestCancelHoldInvoice tests canceling of a hold invoice and related
|
||||||
// notifications.
|
// notifications.
|
||||||
func TestCancelHoldInvoice(t *testing.T) {
|
func TestCancelHoldInvoice(t *testing.T) {
|
||||||
defer timeout(t)()
|
defer timeout()
|
||||||
|
|
||||||
cdb, cleanup, err := newDB()
|
cdb, cleanup, err := newTestChannelDB()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -585,7 +482,7 @@ func TestCancelHoldInvoice(t *testing.T) {
|
|||||||
defer registry.Stop()
|
defer registry.Stop()
|
||||||
|
|
||||||
// Add the invoice.
|
// Add the invoice.
|
||||||
_, err = registry.AddInvoice(testHodlInvoice, hash)
|
_, err = registry.AddInvoice(testHodlInvoice, testInvoicePaymentHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -596,7 +493,7 @@ func TestCancelHoldInvoice(t *testing.T) {
|
|||||||
// NotifyExitHopHtlc without a preimage present in the invoice registry
|
// NotifyExitHopHtlc without a preimage present in the invoice registry
|
||||||
// should be possible.
|
// should be possible.
|
||||||
event, err := registry.NotifyExitHopHtlc(
|
event, err := registry.NotifyExitHopHtlc(
|
||||||
hash, amtPaid, testHtlcExpiry, testCurrentHeight,
|
testInvoicePaymentHash, amtPaid, testHtlcExpiry, testCurrentHeight,
|
||||||
getCircuitKey(0), hodlChan, testPayload,
|
getCircuitKey(0), hodlChan, testPayload,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -607,7 +504,7 @@ func TestCancelHoldInvoice(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Cancel invoice.
|
// Cancel invoice.
|
||||||
err = registry.CancelInvoice(hash)
|
err = registry.CancelInvoice(testInvoicePaymentHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("cancel invoice failed")
|
t.Fatal("cancel invoice failed")
|
||||||
}
|
}
|
||||||
@ -621,7 +518,7 @@ func TestCancelHoldInvoice(t *testing.T) {
|
|||||||
// in a rejection. The accept height is expected to be the original
|
// in a rejection. The accept height is expected to be the original
|
||||||
// accept height.
|
// accept height.
|
||||||
event, err = registry.NotifyExitHopHtlc(
|
event, err = registry.NotifyExitHopHtlc(
|
||||||
hash, amtPaid, testHtlcExpiry, testCurrentHeight+1,
|
testInvoicePaymentHash, amtPaid, testHtlcExpiry, testCurrentHeight+1,
|
||||||
getCircuitKey(0), hodlChan, testPayload,
|
getCircuitKey(0), hodlChan, testPayload,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -636,29 +533,6 @@ func TestCancelHoldInvoice(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newDB() (*channeldb.DB, func(), error) {
|
|
||||||
// First, create a temporary directory to be used for the duration of
|
|
||||||
// this test.
|
|
||||||
tempDirName, err := ioutil.TempDir("", "channeldb")
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Next, create channeldb for the first time.
|
|
||||||
cdb, err := channeldb.Open(tempDirName)
|
|
||||||
if err != nil {
|
|
||||||
os.RemoveAll(tempDirName)
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanUp := func() {
|
|
||||||
cdb.Close()
|
|
||||||
os.RemoveAll(tempDirName)
|
|
||||||
}
|
|
||||||
|
|
||||||
return cdb, cleanUp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestUnknownInvoice tests that invoice registry returns an error when the
|
// TestUnknownInvoice tests that invoice registry returns an error when the
|
||||||
// invoice is unknown. This is to guard against returning a cancel hodl event
|
// invoice is unknown. This is to guard against returning a cancel hodl event
|
||||||
// for forwarded htlcs. In the link, NotifyExitHopHtlc is only called if we are
|
// for forwarded htlcs. In the link, NotifyExitHopHtlc is only called if we are
|
||||||
@ -673,7 +547,7 @@ func TestUnknownInvoice(t *testing.T) {
|
|||||||
hodlChan := make(chan interface{})
|
hodlChan := make(chan interface{})
|
||||||
amt := lnwire.MilliSatoshi(100000)
|
amt := lnwire.MilliSatoshi(100000)
|
||||||
_, err := ctx.registry.NotifyExitHopHtlc(
|
_, err := ctx.registry.NotifyExitHopHtlc(
|
||||||
hash, amt, testHtlcExpiry, testCurrentHeight,
|
testInvoicePaymentHash, amt, testHtlcExpiry, testCurrentHeight,
|
||||||
getCircuitKey(0), hodlChan, testPayload,
|
getCircuitKey(0), hodlChan, testPayload,
|
||||||
)
|
)
|
||||||
if err != channeldb.ErrInvoiceNotFound {
|
if err != channeldb.ErrInvoiceNotFound {
|
||||||
@ -681,27 +555,15 @@ func TestUnknownInvoice(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type mockPayload struct {
|
|
||||||
mpp *record.MPP
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *mockPayload) MultiPath() *record.MPP {
|
|
||||||
return p.mpp
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *mockPayload) CustomRecords() record.CustomSet {
|
|
||||||
return make(record.CustomSet)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestSettleMpp tests settling of an invoice with multiple partial payments.
|
// TestSettleMpp tests settling of an invoice with multiple partial payments.
|
||||||
func TestSettleMpp(t *testing.T) {
|
func TestSettleMpp(t *testing.T) {
|
||||||
defer timeout(t)()
|
defer timeout()
|
||||||
|
|
||||||
ctx := newTestContext(t)
|
ctx := newTestContext(t)
|
||||||
defer ctx.cleanup()
|
defer ctx.cleanup()
|
||||||
|
|
||||||
// Add the invoice.
|
// Add the invoice.
|
||||||
_, err := ctx.registry.AddInvoice(testInvoice, hash)
|
_, err := ctx.registry.AddInvoice(testInvoice, testInvoicePaymentHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -713,7 +575,7 @@ func TestSettleMpp(t *testing.T) {
|
|||||||
// Send htlc 1.
|
// Send htlc 1.
|
||||||
hodlChan1 := make(chan interface{}, 1)
|
hodlChan1 := make(chan interface{}, 1)
|
||||||
event, err := ctx.registry.NotifyExitHopHtlc(
|
event, err := ctx.registry.NotifyExitHopHtlc(
|
||||||
hash, testInvoice.Terms.Value/2,
|
testInvoicePaymentHash, testInvoice.Terms.Value/2,
|
||||||
testHtlcExpiry,
|
testHtlcExpiry,
|
||||||
testCurrentHeight, getCircuitKey(10), hodlChan1, mppPayload,
|
testCurrentHeight, getCircuitKey(10), hodlChan1, mppPayload,
|
||||||
)
|
)
|
||||||
@ -735,7 +597,7 @@ func TestSettleMpp(t *testing.T) {
|
|||||||
// Send htlc 2.
|
// Send htlc 2.
|
||||||
hodlChan2 := make(chan interface{}, 1)
|
hodlChan2 := make(chan interface{}, 1)
|
||||||
event, err = ctx.registry.NotifyExitHopHtlc(
|
event, err = ctx.registry.NotifyExitHopHtlc(
|
||||||
hash, testInvoice.Terms.Value/2,
|
testInvoicePaymentHash, testInvoice.Terms.Value/2,
|
||||||
testHtlcExpiry,
|
testHtlcExpiry,
|
||||||
testCurrentHeight, getCircuitKey(11), hodlChan2, mppPayload,
|
testCurrentHeight, getCircuitKey(11), hodlChan2, mppPayload,
|
||||||
)
|
)
|
||||||
@ -749,7 +611,7 @@ func TestSettleMpp(t *testing.T) {
|
|||||||
// Send htlc 3.
|
// Send htlc 3.
|
||||||
hodlChan3 := make(chan interface{}, 1)
|
hodlChan3 := make(chan interface{}, 1)
|
||||||
event, err = ctx.registry.NotifyExitHopHtlc(
|
event, err = ctx.registry.NotifyExitHopHtlc(
|
||||||
hash, testInvoice.Terms.Value/2,
|
testInvoicePaymentHash, testInvoice.Terms.Value/2,
|
||||||
testHtlcExpiry,
|
testHtlcExpiry,
|
||||||
testCurrentHeight, getCircuitKey(12), hodlChan3, mppPayload,
|
testCurrentHeight, getCircuitKey(12), hodlChan3, mppPayload,
|
||||||
)
|
)
|
||||||
@ -762,7 +624,7 @@ func TestSettleMpp(t *testing.T) {
|
|||||||
|
|
||||||
// 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.
|
||||||
inv, err := ctx.registry.LookupInvoice(hash)
|
inv, err := ctx.registry.LookupInvoice(testInvoicePaymentHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
231
invoices/test_utils_test.go
Normal file
231
invoices/test_utils_test.go
Normal file
@ -0,0 +1,231 @@
|
|||||||
|
package invoices
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"runtime/pprof"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/btcsuite/btcd/btcec"
|
||||||
|
"github.com/btcsuite/btcd/chaincfg"
|
||||||
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
|
"github.com/lightningnetwork/lnd/record"
|
||||||
|
"github.com/lightningnetwork/lnd/zpay32"
|
||||||
|
)
|
||||||
|
|
||||||
|
type mockPayload struct {
|
||||||
|
mpp *record.MPP
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *mockPayload) MultiPath() *record.MPP {
|
||||||
|
return p.mpp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *mockPayload) CustomRecords() record.CustomSet {
|
||||||
|
return make(record.CustomSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
testTimeout = 5 * time.Second
|
||||||
|
|
||||||
|
testTime = time.Date(2018, time.February, 2, 14, 0, 0, 0, time.UTC)
|
||||||
|
|
||||||
|
testInvoicePreimage = lntypes.Preimage{1}
|
||||||
|
|
||||||
|
testInvoicePaymentHash = testInvoicePreimage.Hash()
|
||||||
|
|
||||||
|
testHtlcExpiry = uint32(5)
|
||||||
|
|
||||||
|
testInvoiceCltvDelta = uint32(4)
|
||||||
|
|
||||||
|
testFinalCltvRejectDelta = int32(4)
|
||||||
|
|
||||||
|
testCurrentHeight = int32(1)
|
||||||
|
|
||||||
|
testPrivKeyBytes, _ = hex.DecodeString(
|
||||||
|
"e126f68f7eafcc8b74f54d269fe206be715000f94dac067d1c04a8ca3b2db734")
|
||||||
|
|
||||||
|
testPrivKey, testPubKey = btcec.PrivKeyFromBytes(
|
||||||
|
btcec.S256(), testPrivKeyBytes)
|
||||||
|
|
||||||
|
testInvoiceDescription = "coffee"
|
||||||
|
|
||||||
|
testInvoiceAmount = lnwire.MilliSatoshi(100000)
|
||||||
|
|
||||||
|
testNetParams = &chaincfg.MainNetParams
|
||||||
|
|
||||||
|
testMessageSigner = zpay32.MessageSigner{
|
||||||
|
SignCompact: func(hash []byte) ([]byte, error) {
|
||||||
|
sig, err := btcec.SignCompact(btcec.S256(), testPrivKey, hash, true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("can't sign the message: %v", err)
|
||||||
|
}
|
||||||
|
return sig, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
testFeatures = lnwire.NewFeatureVector(
|
||||||
|
nil, lnwire.Features,
|
||||||
|
)
|
||||||
|
|
||||||
|
testPayload = &mockPayload{}
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
testInvoiceAmt = lnwire.MilliSatoshi(100000)
|
||||||
|
testInvoice = &channeldb.Invoice{
|
||||||
|
Terms: channeldb.ContractTerm{
|
||||||
|
PaymentPreimage: testInvoicePreimage,
|
||||||
|
Value: testInvoiceAmt,
|
||||||
|
Features: testFeatures,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
testHodlInvoice = &channeldb.Invoice{
|
||||||
|
Terms: channeldb.ContractTerm{
|
||||||
|
PaymentPreimage: channeldb.UnknownPreimage,
|
||||||
|
Value: testInvoiceAmt,
|
||||||
|
Features: testFeatures,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func newTestChannelDB() (*channeldb.DB, func(), error) {
|
||||||
|
// First, create a temporary directory to be used for the duration of
|
||||||
|
// this test.
|
||||||
|
tempDirName, err := ioutil.TempDir("", "channeldb")
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next, create channeldb for the first time.
|
||||||
|
cdb, err := channeldb.Open(tempDirName)
|
||||||
|
if err != nil {
|
||||||
|
os.RemoveAll(tempDirName)
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanUp := func() {
|
||||||
|
cdb.Close()
|
||||||
|
os.RemoveAll(tempDirName)
|
||||||
|
}
|
||||||
|
|
||||||
|
return cdb, cleanUp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type testContext struct {
|
||||||
|
registry *InvoiceRegistry
|
||||||
|
clock *testClock
|
||||||
|
|
||||||
|
cleanup func()
|
||||||
|
t *testing.T
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTestContext(t *testing.T) *testContext {
|
||||||
|
clock := newTestClock(testTime)
|
||||||
|
|
||||||
|
cdb, cleanup, err := newTestChannelDB()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
cdb.Now = clock.now
|
||||||
|
|
||||||
|
// Instantiate and start the invoice ctx.registry.
|
||||||
|
cfg := RegistryConfig{
|
||||||
|
FinalCltvRejectDelta: testFinalCltvRejectDelta,
|
||||||
|
HtlcHoldDuration: 30 * time.Second,
|
||||||
|
Now: clock.now,
|
||||||
|
TickAfter: clock.tickAfter,
|
||||||
|
}
|
||||||
|
registry := NewRegistry(cdb, &cfg)
|
||||||
|
|
||||||
|
err = registry.Start()
|
||||||
|
if err != nil {
|
||||||
|
cleanup()
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := testContext{
|
||||||
|
registry: registry,
|
||||||
|
clock: clock,
|
||||||
|
t: t,
|
||||||
|
cleanup: func() {
|
||||||
|
registry.Stop()
|
||||||
|
cleanup()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCircuitKey(htlcID uint64) channeldb.CircuitKey {
|
||||||
|
return channeldb.CircuitKey{
|
||||||
|
ChanID: lnwire.ShortChannelID{
|
||||||
|
BlockHeight: 1, TxIndex: 2, TxPosition: 3,
|
||||||
|
},
|
||||||
|
HtlcID: htlcID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTestInvoice(t *testing.T,
|
||||||
|
timestamp time.Time, expiry time.Duration) *channeldb.Invoice {
|
||||||
|
|
||||||
|
if expiry == 0 {
|
||||||
|
expiry = time.Hour
|
||||||
|
}
|
||||||
|
|
||||||
|
rawInvoice, err := zpay32.NewInvoice(
|
||||||
|
testNetParams,
|
||||||
|
testInvoicePaymentHash,
|
||||||
|
timestamp,
|
||||||
|
zpay32.Amount(testInvoiceAmount),
|
||||||
|
zpay32.Description(testInvoiceDescription),
|
||||||
|
zpay32.Expiry(expiry))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error while creating new invoice: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
paymentRequest, err := rawInvoice.Encode(testMessageSigner)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error while encoding payment request: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &channeldb.Invoice{
|
||||||
|
Terms: channeldb.ContractTerm{
|
||||||
|
PaymentPreimage: testInvoicePreimage,
|
||||||
|
Value: testInvoiceAmount,
|
||||||
|
Expiry: expiry,
|
||||||
|
Features: testFeatures,
|
||||||
|
},
|
||||||
|
PaymentRequest: []byte(paymentRequest),
|
||||||
|
CreationDate: timestamp,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// timeout implements a test level timeout.
|
||||||
|
func timeout() func() {
|
||||||
|
done := make(chan struct{})
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
select {
|
||||||
|
case <-time.After(5 * time.Second):
|
||||||
|
err := pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("error writing to std out after timeout: %v", err))
|
||||||
|
}
|
||||||
|
panic("timeout")
|
||||||
|
case <-done:
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return func() {
|
||||||
|
close(done)
|
||||||
|
}
|
||||||
|
}
|
@ -1,26 +0,0 @@
|
|||||||
package invoices
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"runtime/pprof"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// timeout implements a test level timeout.
|
|
||||||
func timeout(t *testing.T) func() {
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
select {
|
|
||||||
case <-time.After(5 * time.Second):
|
|
||||||
pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
|
|
||||||
|
|
||||||
panic("test timeout")
|
|
||||||
case <-done:
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
return func() {
|
|
||||||
close(done)
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user