Skip to content

Commit 1b1969b

Browse files
GeorgeTsagkguggero
authored andcommitted
itest: add interceptor wire records access test
1 parent a5fcf33 commit 1b1969b

File tree

2 files changed

+105
-3
lines changed

2 files changed

+105
-3
lines changed

itest/list_on_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,10 @@ var allTestCases = []*lntest.TestCase{
430430
Name: "forward interceptor modified htlc",
431431
TestFunc: testForwardInterceptorModifiedHtlc,
432432
},
433+
{
434+
Name: "forward interceptor wire records",
435+
TestFunc: testForwardInterceptorWireRecords,
436+
},
433437
{
434438
Name: "zero conf channel open",
435439
TestFunc: testZeroConfChannelOpen,

itest/lnd_forward_interceptor_test.go

Lines changed: 101 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -479,33 +479,131 @@ func testForwardInterceptorModifiedHtlc(ht *lntest.HarnessTest) {
479479
ht.CloseChannel(bob, cpBC)
480480
}
481481

482+
// testForwardInterceptorWireRecords tests that the interceptor can read any
483+
// wire custom records provided by the sender of a payment as part of the
484+
// update_add_htlc message.
485+
func testForwardInterceptorWireRecords(ht *lntest.HarnessTest) {
486+
// Initialize the test context with 3 connected nodes.
487+
ts := newInterceptorTestScenario(ht)
488+
489+
alice, bob, carol, dave := ts.alice, ts.bob, ts.carol, ts.dave
490+
491+
// Open and wait for channels.
492+
const chanAmt = btcutil.Amount(300000)
493+
p := lntest.OpenChannelParams{Amt: chanAmt}
494+
reqs := []*lntest.OpenChannelRequest{
495+
{Local: alice, Remote: bob, Param: p},
496+
{Local: bob, Remote: carol, Param: p},
497+
{Local: carol, Remote: dave, Param: p},
498+
}
499+
resp := ht.OpenMultiChannelsAsync(reqs)
500+
cpAB, cpBC, cpCD := resp[0], resp[1], resp[2]
501+
502+
// Make sure Alice is aware of channel Bob=>Carol.
503+
ht.AssertTopologyChannelOpen(alice, cpBC)
504+
505+
// Connect an interceptor to Bob's node.
506+
bobInterceptor, cancelBobInterceptor := bob.RPC.HtlcInterceptor()
507+
defer cancelBobInterceptor()
508+
509+
// Also connect an interceptor on Carol's node to check whether we're
510+
// relaying the TLVs send in update_add_htlc over Alice -> Bob on the
511+
// Bob -> Carol link.
512+
carolInterceptor, cancelCarolInterceptor := carol.RPC.HtlcInterceptor()
513+
defer cancelCarolInterceptor()
514+
515+
req := &lnrpc.Invoice{ValueMsat: 1000}
516+
addResponse := dave.RPC.AddInvoice(req)
517+
invoice := dave.RPC.LookupInvoice(addResponse.RHash)
518+
519+
sendReq := &routerrpc.SendPaymentRequest{
520+
PaymentRequest: invoice.PaymentRequest,
521+
TimeoutSeconds: int32(wait.PaymentTimeout.Seconds()),
522+
FeeLimitMsat: noFeeLimitMsat,
523+
FirstHopCustomRecords: map[uint64][]byte{
524+
65537: []byte("test"),
525+
},
526+
}
527+
528+
_ = alice.RPC.SendPayment(sendReq)
529+
530+
// We start the htlc interceptor with a simple implementation that saves
531+
// all intercepted packets. These packets are held to simulate a
532+
// pending payment.
533+
packet := ht.ReceiveHtlcInterceptor(bobInterceptor)
534+
535+
require.Len(ht, packet.IncomingHtlcWireCustomRecords, 1)
536+
537+
val, ok := packet.IncomingHtlcWireCustomRecords[65537]
538+
require.True(ht, ok, "expected custom record")
539+
require.Equal(ht, []byte("test"), val)
540+
541+
action := routerrpc.ResolveHoldForwardAction_RESUME_MODIFIED
542+
newOutgoingAmountMsat := packet.OutgoingAmountMsat + 800
543+
544+
err := bobInterceptor.Send(&routerrpc.ForwardHtlcInterceptResponse{
545+
IncomingCircuitKey: packet.IncomingCircuitKey,
546+
OutgoingAmountMsat: newOutgoingAmountMsat,
547+
Action: action,
548+
})
549+
require.NoError(ht, err, "failed to send request")
550+
551+
// Assert that the Alice -> Bob custom records in update_add_htlc are
552+
// not propagated on the Bob -> Carol link.
553+
packet = ht.ReceiveHtlcInterceptor(carolInterceptor)
554+
require.Len(ht, packet.IncomingHtlcWireCustomRecords, 0)
555+
556+
// Just resume the payment on Carol.
557+
err = carolInterceptor.Send(&routerrpc.ForwardHtlcInterceptResponse{
558+
IncomingCircuitKey: packet.IncomingCircuitKey,
559+
Action: routerrpc.ResolveHoldForwardAction_RESUME,
560+
})
561+
require.NoError(ht, err, "carol interceptor response")
562+
563+
// Assert that the payment was successful.
564+
var preimage lntypes.Preimage
565+
copy(preimage[:], invoice.RPreimage)
566+
ht.AssertPaymentStatus(alice, preimage, lnrpc.Payment_SUCCEEDED)
567+
568+
// Finally, close channels.
569+
ht.CloseChannel(alice, cpAB)
570+
ht.CloseChannel(bob, cpBC)
571+
ht.CloseChannel(carol, cpCD)
572+
}
573+
482574
// interceptorTestScenario is a helper struct to hold the test context and
483575
// provide the needed functionality.
484576
type interceptorTestScenario struct {
485-
ht *lntest.HarnessTest
486-
alice, bob, carol *node.HarnessNode
577+
ht *lntest.HarnessTest
578+
alice, bob, carol, dave *node.HarnessNode
487579
}
488580

489581
// newInterceptorTestScenario initializes a new test scenario with three nodes
490582
// and connects them to have the following topology,
491583
//
492-
// Alice --> Bob --> Carol
584+
// Alice --> Bob --> Carol --> Dave
493585
//
494586
// Among them, Alice and Bob are standby nodes and Carol is a new node.
495587
func newInterceptorTestScenario(
496588
ht *lntest.HarnessTest) *interceptorTestScenario {
497589

498590
alice, bob := ht.Alice, ht.Bob
499591
carol := ht.NewNode("carol", nil)
592+
dave := ht.NewNode("dave", nil)
500593

501594
ht.EnsureConnected(alice, bob)
502595
ht.EnsureConnected(bob, carol)
596+
ht.EnsureConnected(carol, dave)
597+
598+
// So that carol can open channels.
599+
ht.FundCoins(btcutil.SatoshiPerBitcoin, carol)
503600

504601
return &interceptorTestScenario{
505602
ht: ht,
506603
alice: alice,
507604
bob: bob,
508605
carol: carol,
606+
dave: dave,
509607
}
510608
}
511609

0 commit comments

Comments
 (0)