@@ -524,6 +524,43 @@ func (b *blindedForwardTest) interceptFinalHop() func(routerrpc.ResolveHoldForwa
524524 return resolve
525525}
526526
527+ // drainCarolLiquidity will drain all of the liquidity in Carol's channel in
528+ // the direction requested:
529+ // - incoming: Carol has no incoming liquidity from Bob
530+ // - outgoing: Carol has no outgoing liquidity to Dave.
531+ func (b * blindedForwardTest ) drainCarolLiquidity (incoming bool ) {
532+ sendingNode := b .carol
533+ receivingNode := b .dave
534+
535+ if incoming {
536+ sendingNode = b .ht .Bob
537+ receivingNode = b .carol
538+ }
539+
540+ resp := sendingNode .RPC .ListChannels (& lnrpc.ListChannelsRequest {
541+ Peer : receivingNode .PubKey [:],
542+ })
543+ require .Len (b .ht , resp .Channels , 1 )
544+
545+ // We can't send our channel reserve, and leave some buffer for fees.
546+ paymentAmt := resp .Channels [0 ].LocalBalance -
547+ int64 (resp .Channels [0 ].RemoteConstraints .ChanReserveSat ) - 25000
548+
549+ invoice := receivingNode .RPC .AddInvoice (& lnrpc.Invoice {
550+ // Leave some leeway for fees for the HTLC.
551+ Value : paymentAmt ,
552+ })
553+
554+ pmtClient := sendingNode .RPC .SendPayment (
555+ & routerrpc.SendPaymentRequest {
556+ PaymentRequest : invoice .PaymentRequest ,
557+ TimeoutSeconds : 60 ,
558+ },
559+ )
560+
561+ b .ht .AssertPaymentStatusFromStream (pmtClient , lnrpc .Payment_SUCCEEDED )
562+ }
563+
527564// setupFourHopNetwork creates a network with the following topology and
528565// liquidity:
529566// Alice (100k)----- Bob (100k) ----- Carol (100k) ----- Dave
@@ -807,6 +844,26 @@ func testReceiverBlindedError(ht *lntest.HarnessTest) {
807844 sendAndResumeBlindedPayment (ctx , ht , testCase , route )
808845}
809846
847+ // testRelayingBlindedError tests handling of errors from relaying nodes in a
848+ // blinded route, testing a failure over on Carol's outgoing link in the
849+ // following topology: Alice -- Bob -- Carol -- Dave, where Bob is the
850+ // introduction node.
851+ func testRelayingBlindedError (ht * lntest.HarnessTest ) {
852+ ctx , testCase := newBlindedForwardTest (ht )
853+ defer testCase .cleanup ()
854+ route := testCase .setup (ctx )
855+
856+ // Before we send our payment, drain all of Carol's liquidity
857+ // so that she can't forward the payment to Dave.
858+ testCase .drainCarolLiquidity (false )
859+
860+ // Then dispatch the payment through Carol which will fail due to
861+ // a lack of liquidity. This check only happens _after_ the interceptor
862+ // has given the instruction to resume so we can use test
863+ // infrastructure that will go ahead and intercept the payment.
864+ sendAndResumeBlindedPayment (ctx , ht , testCase , route )
865+ }
866+
810867// sendAndResumeBlindedPayment sends a blinded payment through the test
811868// network provided, intercepting the payment at Carol and allowing it to
812869// resume. This utility function allows us to ensure that payments at least
0 commit comments