Skip to content

Commit 9a972e1

Browse files
ffranrguggero
authored andcommitted
itest: add basic invoice HTLC modifier integration test
This commit introduces a basic integration test for the invoice HTLC modifier. The test covers scenarios where an invoice is settled with a payment that is less than the invoice amount, facilitated by the invoice HTLC modifier.
1 parent d37df75 commit 9a972e1

File tree

3 files changed

+421
-21
lines changed

3 files changed

+421
-21
lines changed

itest/list_on_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,10 @@ var allTestCases = []*lntest.TestCase{
466466
Name: "forward interceptor restart",
467467
TestFunc: testForwardInterceptorRestart,
468468
},
469+
{
470+
Name: "invoice HTLC modifier basic",
471+
TestFunc: testInvoiceHtlcModifierBasic,
472+
},
469473
{
470474
Name: "zero conf channel open",
471475
TestFunc: testZeroConfChannelOpen,

itest/lnd_forward_interceptor_test.go

Lines changed: 59 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/btcsuite/btcd/btcutil"
1111
"github.com/lightningnetwork/lnd/chainreg"
1212
"github.com/lightningnetwork/lnd/lnrpc"
13+
"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
1314
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
1415
"github.com/lightningnetwork/lnd/lntest"
1516
"github.com/lightningnetwork/lnd/lntest/node"
@@ -374,8 +375,13 @@ func testForwardInterceptorModifiedHtlc(ht *lntest.HarnessTest) {
374375
// Connect an interceptor to Bob's node.
375376
bobInterceptor, cancelBobInterceptor := bob.RPC.HtlcInterceptor()
376377

378+
// We're going to modify the payment amount and want Carol to accept the
379+
// payment, so we set up an invoice acceptor on Dave.
380+
carolAcceptor, carolCancel := carol.RPC.InvoiceHtlcModifier()
381+
defer carolCancel()
382+
377383
// Prepare the test cases.
378-
invoiceValueAmtMsat := int64(1000)
384+
invoiceValueAmtMsat := int64(20_000_000)
379385
req := &lnrpc.Invoice{ValueMsat: invoiceValueAmtMsat}
380386
addResponse := carol.RPC.AddInvoice(req)
381387
invoice := carol.RPC.LookupInvoice(addResponse.RHash)
@@ -408,10 +414,10 @@ func testForwardInterceptorModifiedHtlc(ht *lntest.HarnessTest) {
408414
crValue := []byte("custom-records-test-value")
409415
customRecords[crKey] = crValue
410416

411-
// TODO(guggero): Actually modify the amount once we have the invoice
412-
// interceptor and can accept a lower amount.
413-
newOutAmountMsat := packet.OutgoingAmountMsat
414-
417+
// Modify the amount of the HTLC, so we send out less than the original
418+
// amount.
419+
const modifyAmount = 5_000_000
420+
newOutAmountMsat := packet.OutgoingAmountMsat - modifyAmount
415421
err := bobInterceptor.Send(&routerrpc.ForwardHtlcInterceptResponse{
416422
IncomingCircuitKey: packet.IncomingCircuitKey,
417423
OutAmountMsat: newOutAmountMsat,
@@ -420,6 +426,17 @@ func testForwardInterceptorModifiedHtlc(ht *lntest.HarnessTest) {
420426
})
421427
require.NoError(ht, err, "failed to send request")
422428

429+
invoicePacket := ht.ReceiveInvoiceHtlcModification(carolAcceptor)
430+
require.EqualValues(
431+
ht, newOutAmountMsat, invoicePacket.ExitHtlcAmt,
432+
)
433+
amtPaid := newOutAmountMsat + modifyAmount
434+
err = carolAcceptor.Send(&invoicesrpc.HtlcModifyResponse{
435+
CircuitKey: invoicePacket.ExitHtlcCircuitKey,
436+
AmtPaid: &amtPaid,
437+
})
438+
require.NoError(ht, err, "carol acceptor response")
439+
423440
// Cancel the context, which will disconnect Bob's interceptor.
424441
cancelBobInterceptor()
425442

@@ -473,17 +490,23 @@ func testForwardInterceptorWireRecords(ht *lntest.HarnessTest) {
473490
carolInterceptor, cancelCarolInterceptor := carol.RPC.HtlcInterceptor()
474491
defer cancelCarolInterceptor()
475492

476-
req := &lnrpc.Invoice{ValueMsat: 1000}
493+
// We're going to modify the payment amount and want Dave to accept the
494+
// payment, so we set up an invoice acceptor on Dave.
495+
daveAcceptor, daveCancel := dave.RPC.InvoiceHtlcModifier()
496+
defer daveCancel()
497+
498+
req := &lnrpc.Invoice{ValueMsat: 20_000_000}
477499
addResponse := dave.RPC.AddInvoice(req)
478500
invoice := dave.RPC.LookupInvoice(addResponse.RHash)
479501

502+
customRecords := map[uint64][]byte{
503+
65537: []byte("test"),
504+
}
480505
sendReq := &routerrpc.SendPaymentRequest{
481-
PaymentRequest: invoice.PaymentRequest,
482-
TimeoutSeconds: int32(wait.PaymentTimeout.Seconds()),
483-
FeeLimitMsat: noFeeLimitMsat,
484-
FirstHopCustomRecords: map[uint64][]byte{
485-
65537: []byte("test"),
486-
},
506+
PaymentRequest: invoice.PaymentRequest,
507+
TimeoutSeconds: int32(wait.PaymentTimeout.Seconds()),
508+
FeeLimitMsat: noFeeLimitMsat,
509+
FirstHopCustomRecords: customRecords,
487510
}
488511

489512
_ = alice.RPC.SendPayment(sendReq)
@@ -499,14 +522,10 @@ func testForwardInterceptorWireRecords(ht *lntest.HarnessTest) {
499522
require.True(ht, ok, "expected custom record")
500523
require.Equal(ht, []byte("test"), val)
501524

502-
// TODO(guggero): Actually modify the amount once we have the invoice
503-
// interceptor and can accept a lower amount.
504-
newOutAmountMsat := packet.OutgoingAmountMsat
505-
525+
// Just resume the payment on Bob.
506526
err := bobInterceptor.Send(&routerrpc.ForwardHtlcInterceptResponse{
507527
IncomingCircuitKey: packet.IncomingCircuitKey,
508-
OutAmountMsat: newOutAmountMsat,
509-
Action: actionResumeModify,
528+
Action: actionResume,
510529
})
511530
require.NoError(ht, err, "failed to send request")
512531

@@ -515,13 +534,32 @@ func testForwardInterceptorWireRecords(ht *lntest.HarnessTest) {
515534
packet = ht.ReceiveHtlcInterceptor(carolInterceptor)
516535
require.Len(ht, packet.InWireCustomRecords, 0)
517536

518-
// Just resume the payment on Carol.
537+
// We're going to tell Carol to forward 5k sats less to Dave. We need to
538+
// set custom records on the HTLC as well, to make sure the HTLC isn't
539+
// rejected outright and actually gets to the invoice acceptor.
540+
const modifyAmount = 5_000_000
541+
newOutAmountMsat := packet.OutgoingAmountMsat - modifyAmount
519542
err = carolInterceptor.Send(&routerrpc.ForwardHtlcInterceptResponse{
520-
IncomingCircuitKey: packet.IncomingCircuitKey,
521-
Action: actionResume,
543+
IncomingCircuitKey: packet.IncomingCircuitKey,
544+
OutAmountMsat: newOutAmountMsat,
545+
OutWireCustomRecords: customRecords,
546+
Action: actionResumeModify,
522547
})
523548
require.NoError(ht, err, "carol interceptor response")
524549

550+
// The payment should get to Dave, and we should be able to intercept
551+
// and modify it, telling Dave to accept it.
552+
invoicePacket := ht.ReceiveInvoiceHtlcModification(daveAcceptor)
553+
require.EqualValues(
554+
ht, newOutAmountMsat, invoicePacket.ExitHtlcAmt,
555+
)
556+
amtPaid := newOutAmountMsat + modifyAmount
557+
err = daveAcceptor.Send(&invoicesrpc.HtlcModifyResponse{
558+
CircuitKey: invoicePacket.ExitHtlcCircuitKey,
559+
AmtPaid: &amtPaid,
560+
})
561+
require.NoError(ht, err, "dave acceptor response")
562+
525563
// Assert that the payment was successful.
526564
var preimage lntypes.Preimage
527565
copy(preimage[:], invoice.RPreimage)

0 commit comments

Comments
 (0)