mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-11-20 11:06:54 +01:00
itest: refactor testSendPaymentAMPInvoiceRepeat
This commit is contained in:
@@ -397,4 +397,8 @@ var allTestCasesTemp = []*lntemp.TestCase{
|
|||||||
Name: "sendpayment amp invoice",
|
Name: "sendpayment amp invoice",
|
||||||
TestFunc: testSendPaymentAMPInvoice,
|
TestFunc: testSendPaymentAMPInvoice,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "sendpayment amp invoice repeat",
|
||||||
|
TestFunc: testSendPaymentAMPInvoiceRepeat,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -199,167 +199,141 @@ func testSendPaymentAMPInvoiceCase(ht *lntemp.HarnessTest,
|
|||||||
|
|
||||||
// testSendPaymentAMPInvoiceRepeat tests that it's possible to pay an AMP
|
// testSendPaymentAMPInvoiceRepeat tests that it's possible to pay an AMP
|
||||||
// invoice multiple times by having the client generate a new setID each time.
|
// invoice multiple times by having the client generate a new setID each time.
|
||||||
func testSendPaymentAMPInvoiceRepeat(net *lntest.NetworkHarness,
|
func testSendPaymentAMPInvoiceRepeat(ht *lntemp.HarnessTest) {
|
||||||
t *harnessTest) {
|
|
||||||
|
|
||||||
// In this basic test, we'll only need two nodes as we want to
|
// In this basic test, we'll only need two nodes as we want to
|
||||||
// primarily test the recurring payment feature. So we'll re-use the
|
// primarily test the recurring payment feature. So we'll re-use the
|
||||||
carol := net.NewNode(t.t, "Carol", nil)
|
carol := ht.NewNode("Carol", nil)
|
||||||
defer shutdownAndAssert(net, t, carol)
|
|
||||||
|
|
||||||
// Send Carol enough coins to be able to open a channel to Dave.
|
// Send Carol enough coins to be able to open a channel to Dave.
|
||||||
net.SendCoins(t.t, btcutil.SatoshiPerBitcoin, carol)
|
ht.FundCoins(btcutil.SatoshiPerBitcoin, carol)
|
||||||
|
|
||||||
dave := net.NewNode(t.t, "Dave", nil)
|
dave := ht.NewNode("Dave", nil)
|
||||||
defer shutdownAndAssert(net, t, dave)
|
|
||||||
|
|
||||||
// Before we start the test, we'll ensure both sides are connected to
|
|
||||||
// the funding flow can properly be executed.
|
|
||||||
net.EnsureConnected(t.t, carol, dave)
|
|
||||||
|
|
||||||
// Set up an invoice subscription so we can be notified when Dave
|
// Set up an invoice subscription so we can be notified when Dave
|
||||||
// receives his repeated payments.
|
// receives his repeated payments.
|
||||||
req := &lnrpc.InvoiceSubscription{}
|
req := &lnrpc.InvoiceSubscription{}
|
||||||
ctxb := context.Background()
|
invSubscription := dave.RPC.SubscribeInvoices(req)
|
||||||
ctxc, cancelSubscription := context.WithCancel(ctxb)
|
|
||||||
invSubscription, err := dave.SubscribeInvoices(ctxc, req)
|
// Before we start the test, we'll ensure both sides are connected to
|
||||||
require.NoError(t.t, err)
|
// the funding flow can properly be executed.
|
||||||
defer cancelSubscription()
|
ht.EnsureConnected(carol, dave)
|
||||||
|
|
||||||
// Establish a channel between Carol and Dave.
|
// Establish a channel between Carol and Dave.
|
||||||
chanAmt := btcutil.Amount(100_000)
|
chanAmt := btcutil.Amount(100_000)
|
||||||
chanPoint := openChannelAndAssert(
|
ht.OpenChannel(
|
||||||
t, net, carol, dave,
|
carol, dave, lntemp.OpenChannelParams{Amt: chanAmt},
|
||||||
lntest.OpenChannelParams{
|
|
||||||
Amt: chanAmt,
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
err = carol.WaitForNetworkChannelOpen(chanPoint)
|
|
||||||
require.NoError(t.t, err, "carol didn't report channel")
|
|
||||||
err = dave.WaitForNetworkChannelOpen(chanPoint)
|
|
||||||
require.NoError(t.t, err, "dave didn't report channel")
|
|
||||||
|
|
||||||
// Create an AMP invoice of a trivial amount, that we'll pay repeatedly
|
// Create an AMP invoice of a trivial amount, that we'll pay repeatedly
|
||||||
// in this integration test.
|
// in this integration test.
|
||||||
paymentAmt := 10000
|
paymentAmt := 10000
|
||||||
addInvoiceResp, err := dave.AddInvoice(ctxb, &lnrpc.Invoice{
|
invoice := &lnrpc.Invoice{
|
||||||
Value: int64(paymentAmt),
|
Value: int64(paymentAmt),
|
||||||
IsAmp: true,
|
IsAmp: true,
|
||||||
})
|
}
|
||||||
require.NoError(t.t, err)
|
addInvoiceResp := dave.RPC.AddInvoice(invoice)
|
||||||
|
|
||||||
// We should get an initial notification that the HTLC has been added.
|
// We should get an initial notification that the HTLC has been added.
|
||||||
rpcInvoice, err := invSubscription.Recv()
|
rpcInvoice := ht.ReceiveInvoiceUpdate(invSubscription)
|
||||||
require.NoError(t.t, err)
|
require.False(ht, rpcInvoice.Settled) // nolint:staticcheck
|
||||||
require.False(t.t, rpcInvoice.Settled) // nolint:staticcheck
|
require.Equal(ht, lnrpc.Invoice_OPEN, rpcInvoice.State)
|
||||||
require.Equal(t.t, lnrpc.Invoice_OPEN, rpcInvoice.State)
|
require.Equal(ht, int64(0), rpcInvoice.AmtPaidSat)
|
||||||
require.Equal(t.t, int64(0), rpcInvoice.AmtPaidSat)
|
require.Equal(ht, int64(0), rpcInvoice.AmtPaidMsat)
|
||||||
require.Equal(t.t, int64(0), rpcInvoice.AmtPaidMsat)
|
require.Equal(ht, 0, len(rpcInvoice.Htlcs))
|
||||||
|
|
||||||
require.Equal(t.t, 0, len(rpcInvoice.Htlcs))
|
|
||||||
|
|
||||||
// Now we'll use Carol to pay the invoice that Dave created.
|
// Now we'll use Carol to pay the invoice that Dave created.
|
||||||
_ = sendAndAssertSuccess(
|
ht.CompletePaymentRequests(
|
||||||
t, carol, &routerrpc.SendPaymentRequest{
|
carol, []string{addInvoiceResp.PaymentRequest},
|
||||||
PaymentRequest: addInvoiceResp.PaymentRequest,
|
|
||||||
TimeoutSeconds: 60,
|
|
||||||
FeeLimitMsat: noFeeLimitMsat,
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Dave should get a notification that the invoice has been settled.
|
// Dave should get a notification that the invoice has been settled.
|
||||||
invoiceNtfn, err := invSubscription.Recv()
|
invoiceNtfn := ht.ReceiveInvoiceUpdate(invSubscription)
|
||||||
require.NoError(t.t, err)
|
|
||||||
|
|
||||||
// The notification should signal that the invoice is now settled, and
|
// The notification should signal that the invoice is now settled, and
|
||||||
// should also include the set ID, and show the proper amount paid.
|
// should also include the set ID, and show the proper amount paid.
|
||||||
require.True(t.t, invoiceNtfn.Settled) // nolint:staticcheck
|
require.True(ht, invoiceNtfn.Settled) // nolint:staticcheck
|
||||||
require.Equal(t.t, lnrpc.Invoice_SETTLED, invoiceNtfn.State)
|
require.Equal(ht, lnrpc.Invoice_SETTLED, invoiceNtfn.State)
|
||||||
require.Equal(t.t, paymentAmt, int(invoiceNtfn.AmtPaidSat))
|
require.Equal(ht, paymentAmt, int(invoiceNtfn.AmtPaidSat))
|
||||||
require.Equal(t.t, 1, len(invoiceNtfn.AmpInvoiceState))
|
require.Equal(ht, 1, len(invoiceNtfn.AmpInvoiceState))
|
||||||
var firstSetID []byte
|
var firstSetID []byte
|
||||||
for setIDStr, ampState := range invoiceNtfn.AmpInvoiceState {
|
for setIDStr, ampState := range invoiceNtfn.AmpInvoiceState {
|
||||||
firstSetID, _ = hex.DecodeString(setIDStr)
|
firstSetID, _ = hex.DecodeString(setIDStr)
|
||||||
require.Equal(t.t, lnrpc.InvoiceHTLCState_SETTLED, ampState.State)
|
require.Equal(ht, lnrpc.InvoiceHTLCState_SETTLED,
|
||||||
|
ampState.State)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pay the invoice again, we should get another notification that Dave
|
// Pay the invoice again, we should get another notification that Dave
|
||||||
// has received another payment.
|
// has received another payment.
|
||||||
_ = sendAndAssertSuccess(
|
ht.CompletePaymentRequests(
|
||||||
t, carol, &routerrpc.SendPaymentRequest{
|
carol, []string{addInvoiceResp.PaymentRequest},
|
||||||
PaymentRequest: addInvoiceResp.PaymentRequest,
|
|
||||||
TimeoutSeconds: 60,
|
|
||||||
FeeLimitMsat: noFeeLimitMsat,
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Dave should get another notification.
|
// Dave should get another notification.
|
||||||
invoiceNtfn, err = invSubscription.Recv()
|
invoiceNtfn = ht.ReceiveInvoiceUpdate(invSubscription)
|
||||||
require.NoError(t.t, err)
|
|
||||||
|
|
||||||
// The invoice should still be shown as settled, and also include the
|
// The invoice should still be shown as settled, and also include the
|
||||||
// information about this newly generated setID, showing 2x the amount
|
// information about this newly generated setID, showing 2x the amount
|
||||||
// paid.
|
// paid.
|
||||||
require.True(t.t, invoiceNtfn.Settled) // nolint:staticcheck
|
require.True(ht, invoiceNtfn.Settled) // nolint:staticcheck
|
||||||
require.Equal(t.t, paymentAmt*2, int(invoiceNtfn.AmtPaidSat))
|
require.Equal(ht, paymentAmt*2, int(invoiceNtfn.AmtPaidSat))
|
||||||
|
|
||||||
var secondSetID []byte
|
var secondSetID []byte
|
||||||
for setIDStr, ampState := range invoiceNtfn.AmpInvoiceState {
|
for setIDStr, ampState := range invoiceNtfn.AmpInvoiceState {
|
||||||
secondSetID, _ = hex.DecodeString(setIDStr)
|
secondSetID, _ = hex.DecodeString(setIDStr)
|
||||||
require.Equal(t.t, lnrpc.InvoiceHTLCState_SETTLED, ampState.State)
|
require.Equal(ht, lnrpc.InvoiceHTLCState_SETTLED,
|
||||||
|
ampState.State)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The returned invoice should only include a single HTLC since we
|
// The returned invoice should only include a single HTLC since we
|
||||||
// return the "projected" sub-invoice for a given setID.
|
// return the "projected" sub-invoice for a given setID.
|
||||||
require.Equal(t.t, 1, len(invoiceNtfn.Htlcs))
|
require.Equal(ht, 1, len(invoiceNtfn.Htlcs))
|
||||||
|
|
||||||
// However the AMP state index should show that there've been two
|
// However the AMP state index should show that there've been two
|
||||||
// repeated payments to this invoice so far.
|
// repeated payments to this invoice so far.
|
||||||
require.Equal(t.t, 2, len(invoiceNtfn.AmpInvoiceState))
|
require.Equal(ht, 2, len(invoiceNtfn.AmpInvoiceState))
|
||||||
|
|
||||||
// Now we'll look up the invoice using the new LookupInvoice2 RPC call
|
// Now we'll look up the invoice using the new LookupInvoice2 RPC call
|
||||||
// by the set ID of each of the invoices.
|
// by the set ID of each of the invoices.
|
||||||
subInvoice1, err := dave.LookupInvoiceV2(ctxb, &invoicesrpc.LookupInvoiceMsg{
|
msg := &invoicesrpc.LookupInvoiceMsg{
|
||||||
InvoiceRef: &invoicesrpc.LookupInvoiceMsg_SetId{
|
InvoiceRef: &invoicesrpc.LookupInvoiceMsg_SetId{
|
||||||
SetId: firstSetID,
|
SetId: firstSetID,
|
||||||
},
|
},
|
||||||
LookupModifier: invoicesrpc.LookupModifier_HTLC_SET_ONLY,
|
LookupModifier: invoicesrpc.LookupModifier_HTLC_SET_ONLY,
|
||||||
})
|
}
|
||||||
require.Nil(t.t, err)
|
subInvoice1 := dave.RPC.LookupInvoiceV2(msg)
|
||||||
subInvoice2, err := dave.LookupInvoiceV2(ctxb, &invoicesrpc.LookupInvoiceMsg{
|
msg = &invoicesrpc.LookupInvoiceMsg{
|
||||||
InvoiceRef: &invoicesrpc.LookupInvoiceMsg_SetId{
|
InvoiceRef: &invoicesrpc.LookupInvoiceMsg_SetId{
|
||||||
SetId: secondSetID,
|
SetId: secondSetID,
|
||||||
},
|
},
|
||||||
LookupModifier: invoicesrpc.LookupModifier_HTLC_SET_ONLY,
|
LookupModifier: invoicesrpc.LookupModifier_HTLC_SET_ONLY,
|
||||||
})
|
}
|
||||||
require.Nil(t.t, err)
|
subInvoice2 := dave.RPC.LookupInvoiceV2(msg)
|
||||||
|
|
||||||
// Each invoice should only show a single HTLC present, as we passed
|
// Each invoice should only show a single HTLC present, as we passed
|
||||||
// the HTLC set only modifier.
|
// the HTLC set only modifier.
|
||||||
require.Equal(t.t, 1, len(subInvoice1.Htlcs))
|
require.Equal(ht, 1, len(subInvoice1.Htlcs))
|
||||||
require.Equal(t.t, 1, len(subInvoice2.Htlcs))
|
require.Equal(ht, 1, len(subInvoice2.Htlcs))
|
||||||
|
|
||||||
// If we look up the same invoice, by its payment address, but now with
|
// If we look up the same invoice, by its payment address, but now with
|
||||||
// the HTLC blank modifier, then none of them should be returned.
|
// the HTLC blank modifier, then none of them should be returned.
|
||||||
rootInvoice, err := dave.LookupInvoiceV2(ctxb, &invoicesrpc.LookupInvoiceMsg{
|
msg = &invoicesrpc.LookupInvoiceMsg{
|
||||||
InvoiceRef: &invoicesrpc.LookupInvoiceMsg_PaymentAddr{
|
InvoiceRef: &invoicesrpc.LookupInvoiceMsg_PaymentAddr{
|
||||||
PaymentAddr: addInvoiceResp.PaymentAddr,
|
PaymentAddr: addInvoiceResp.PaymentAddr,
|
||||||
},
|
},
|
||||||
LookupModifier: invoicesrpc.LookupModifier_HTLC_SET_BLANK,
|
LookupModifier: invoicesrpc.LookupModifier_HTLC_SET_BLANK,
|
||||||
})
|
}
|
||||||
require.Nil(t.t, err)
|
rootInvoice := dave.RPC.LookupInvoiceV2(msg)
|
||||||
require.Equal(t.t, 0, len(rootInvoice.Htlcs))
|
require.Equal(ht, 0, len(rootInvoice.Htlcs))
|
||||||
|
|
||||||
// If we look up the same invoice, by its payment address, but without
|
// If we look up the same invoice, by its payment address, but without
|
||||||
// that modified, then we should get all the relevant HTLCs.
|
// that modified, then we should get all the relevant HTLCs.
|
||||||
rootInvoice, err = dave.LookupInvoiceV2(ctxb,
|
msg = &invoicesrpc.LookupInvoiceMsg{
|
||||||
&invoicesrpc.LookupInvoiceMsg{
|
InvoiceRef: &invoicesrpc.LookupInvoiceMsg_PaymentAddr{
|
||||||
InvoiceRef: &invoicesrpc.LookupInvoiceMsg_PaymentAddr{
|
PaymentAddr: addInvoiceResp.PaymentAddr,
|
||||||
PaymentAddr: addInvoiceResp.PaymentAddr,
|
},
|
||||||
},
|
}
|
||||||
})
|
rootInvoice = dave.RPC.LookupInvoiceV2(msg)
|
||||||
require.Nil(t.t, err)
|
require.Equal(ht, 2, len(rootInvoice.Htlcs))
|
||||||
require.Equal(t.t, 2, len(rootInvoice.Htlcs))
|
|
||||||
|
|
||||||
// Finally, we'll test that if we subscribe for notifications of
|
// Finally, we'll test that if we subscribe for notifications of
|
||||||
// settled invoices, we get a backlog, which includes the invoice we
|
// settled invoices, we get a backlog, which includes the invoice we
|
||||||
@@ -368,19 +342,16 @@ func testSendPaymentAMPInvoiceRepeat(net *lntest.NetworkHarness,
|
|||||||
req = &lnrpc.InvoiceSubscription{
|
req = &lnrpc.InvoiceSubscription{
|
||||||
SettleIndex: 1,
|
SettleIndex: 1,
|
||||||
}
|
}
|
||||||
ctxc, cancelSubscription2 := context.WithCancel(ctxb)
|
invSub2 := dave.RPC.SubscribeInvoices(req)
|
||||||
invSub2, err := dave.SubscribeInvoices(ctxc, req)
|
|
||||||
require.NoError(t.t, err)
|
|
||||||
defer cancelSubscription2()
|
|
||||||
|
|
||||||
// The first invoice we get back should match the state of the invoice
|
// The first invoice we get back should match the state of the invoice
|
||||||
// after our second payment: amt updated, but only a single HTLC shown
|
// after our second payment: amt updated, but only a single HTLC shown
|
||||||
// through.
|
// through.
|
||||||
backlogInv, _ := invSub2.Recv()
|
backlogInv := ht.ReceiveInvoiceUpdate(invSub2)
|
||||||
require.Equal(t.t, 1, len(backlogInv.Htlcs))
|
require.Equal(ht, 1, len(backlogInv.Htlcs))
|
||||||
require.Equal(t.t, 2, len(backlogInv.AmpInvoiceState))
|
require.Equal(ht, 2, len(backlogInv.AmpInvoiceState))
|
||||||
require.True(t.t, backlogInv.Settled) // nolint:staticcheck
|
require.True(ht, backlogInv.Settled) // nolint:staticcheck
|
||||||
require.Equal(t.t, paymentAmt*2, int(backlogInv.AmtPaidSat))
|
require.Equal(ht, paymentAmt*2, int(backlogInv.AmtPaidSat))
|
||||||
}
|
}
|
||||||
|
|
||||||
// testSendPaymentAMP tests that we can send an AMP payment to a specified
|
// testSendPaymentAMP tests that we can send an AMP payment to a specified
|
||||||
|
|||||||
@@ -48,10 +48,6 @@ var allTestCases = []*testCase{
|
|||||||
name: "sendpayment amp",
|
name: "sendpayment amp",
|
||||||
test: testSendPaymentAMP,
|
test: testSendPaymentAMP,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "sendpayment amp invoice repeat",
|
|
||||||
test: testSendPaymentAMPInvoiceRepeat,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "forward interceptor",
|
name: "forward interceptor",
|
||||||
test: testForwardInterceptorBasic,
|
test: testForwardInterceptorBasic,
|
||||||
|
|||||||
Reference in New Issue
Block a user