@@ -28,6 +28,7 @@ import (
2828 "github.com/lightningnetwork/lnd/fn"
2929 "github.com/lightningnetwork/lnd/lnrpc"
3030 "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
31+ "github.com/lightningnetwork/lnd/lnrpc/routerrpc"
3132 "github.com/lightningnetwork/lnd/lntest"
3233 "github.com/lightningnetwork/lnd/lntest/node"
3334 "github.com/lightningnetwork/lnd/lntest/port"
@@ -2239,12 +2240,12 @@ func testCustomChannelsBreach(ctx context.Context, net *NetworkHarness,
22392240 t .Logf ("Charlie balance after breach: %d" , charlieBalance )
22402241}
22412242
2242- // testCustomChannelsLiquidtyEdgeCasesCore is the core logic of the liquidity
2243+ // testCustomChannelsLiquidityEdgeCasesCore is the core logic of the liquidity
22432244// edge cases. This test goes through certain scenarios that expose edge cases
22442245// and behaviors that proved to be buggy in the past and have been directly
22452246// addressed. It accepts an extra parameter which dictates whether it should use
22462247// group keys or asset IDs.
2247- func testCustomChannelsLiquidtyEdgeCasesCore (ctx context.Context ,
2248+ func testCustomChannelsLiquidityEdgeCasesCore (ctx context.Context ,
22482249 net * NetworkHarness , t * harnessTest , groupMode bool ) {
22492250
22502251 lndArgs := slices .Clone (lndArgsTemplate )
@@ -2742,6 +2743,69 @@ func testCustomChannelsLiquidtyEdgeCasesCore(ctx context.Context,
27422743 )
27432744
27442745 logBalance (t .t , nodes , assetID , "after small manual rfq" )
2746+
2747+ // Edge case: Fabia creates an invoice which Erin cannot satisfy with
2748+ // his side of asset liquidity. This tests that Erin will not try to
2749+ // add an HTLC with more asset units than what his local balance is. To
2750+ // validate that the channel is still healthy, we follow up with a
2751+ // smaller invoice payment which is meant to succeed.
2752+
2753+ // We now create a hodl invoice on Fabia, for 125k assets.
2754+ hodlInv = createAssetHodlInvoice (t .t , erin , fabia , 125_000 , assetID )
2755+
2756+ htlcStream , err := erin .RouterClient .SubscribeHtlcEvents (
2757+ ctx , & routerrpc.SubscribeHtlcEventsRequest {},
2758+ )
2759+ require .NoError (t .t , err )
2760+
2761+ // Charlie tries to pay, this is not meant to succeed, as Erin does not
2762+ // have enough assets to forward to Fabia.
2763+ payInvoiceWithAssets (
2764+ t .t , charlie , dave , hodlInv .payReq , assetID ,
2765+ withFailure (lnrpc .Payment_IN_FLIGHT , failureNone ),
2766+ )
2767+
2768+ // Let's check that at least 2 HTLCs were added on the Erin->Fabia link,
2769+ // which means that Erin would have an extra incoming HTLC for each
2770+ // outgoing one. So we expect a minimum of 4 HTLCs present on Erin.
2771+ assertMinNumHtlcs (t .t , erin , 4 )
2772+
2773+ // We also want to make sure that at least one failure occurred that
2774+ // hinted at the problem (not enough assets to forward).
2775+ assertHtlcEvents (
2776+ t .t , htlcStream , withNumEvents (1 ),
2777+ withLinkFailure (routerrpc .FailureDetail_INSUFFICIENT_BALANCE ),
2778+ )
2779+
2780+ logBalance (t .t , nodes , assetID , "with min 4 present HTLCs" )
2781+
2782+ // Now Fabia cancels the invoice, this is meant to cancel back any
2783+ // locked in HTLCs and reset Erin's local balance back to its original
2784+ // value.
2785+ payHash = hodlInv .preimage .Hash ()
2786+ _ , err = fabia .InvoicesClient .CancelInvoice (
2787+ ctx , & invoicesrpc.CancelInvoiceMsg {
2788+ PaymentHash : payHash [:],
2789+ },
2790+ )
2791+ require .NoError (t .t , err )
2792+
2793+ // Let's assert that Erin cancelled all his HTLCs.
2794+ assertNumHtlcs (t .t , erin , 0 )
2795+
2796+ logBalance (t .t , nodes , assetID , "after hodl cancel & 0 present HTLCs" )
2797+
2798+ // Now let's create a smaller invoice and pay it, to validate that the
2799+ // channel is still healthy.
2800+ invoiceResp = createAssetInvoice (
2801+ t .t , erin , fabia , 50_000 , assetID ,
2802+ )
2803+
2804+ payInvoiceWithAssets (
2805+ t .t , charlie , dave , invoiceResp .PaymentRequest , assetID ,
2806+ )
2807+
2808+ logBalance (t .t , nodes , assetID , "after safe asset htlc failure" )
27452809}
27462810
27472811// testCustomChannelsLiquidityEdgeCases is a test that runs through some
@@ -2751,7 +2815,7 @@ func testCustomChannelsLiquidityEdgeCases(ctx context.Context,
27512815
27522816 // Run liquidity edge cases and only use single asset IDs for invoices
27532817 // and payments.
2754- testCustomChannelsLiquidtyEdgeCasesCore (ctx , net , t , false )
2818+ testCustomChannelsLiquidityEdgeCasesCore (ctx , net , t , false )
27552819}
27562820
27572821// testCustomChannelsLiquidityEdgeCasesGroup is a test that runs through some
@@ -2761,7 +2825,7 @@ func testCustomChannelsLiquidityEdgeCasesGroup(ctx context.Context,
27612825
27622826 // Run liquidity edge cases and only use group keys for invoices and
27632827 // payments.
2764- testCustomChannelsLiquidtyEdgeCasesCore (ctx , net , t , true )
2828+ testCustomChannelsLiquidityEdgeCasesCore (ctx , net , t , true )
27652829}
27662830
27672831// testCustomChannelsStrictForwarding is a test that tests the strict forwarding
0 commit comments