@@ -30,6 +30,7 @@ import (
3030 "github.com/lightningnetwork/lnd/fn"
3131 "github.com/lightningnetwork/lnd/lnrpc"
3232 "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
33+ "github.com/lightningnetwork/lnd/lnrpc/routerrpc"
3334 "github.com/lightningnetwork/lnd/lnrpc/walletrpc"
3435 "github.com/lightningnetwork/lnd/lntest"
3536 "github.com/lightningnetwork/lnd/lntest/node"
@@ -2601,12 +2602,12 @@ func testCustomChannelsBreach(ctx context.Context, net *NetworkHarness,
26012602 t .Logf ("Charlie UTXOs after breach: %v" , toProtoJSON (t .t , charlieUTXOs ))
26022603}
26032604
2604- // testCustomChannelsLiquidtyEdgeCasesCore is the core logic of the liquidity
2605+ // testCustomChannelsLiquidityEdgeCasesCore is the core logic of the liquidity
26052606// edge cases. This test goes through certain scenarios that expose edge cases
26062607// and behaviors that proved to be buggy in the past and have been directly
26072608// addressed. It accepts an extra parameter which dictates whether it should use
26082609// group keys or asset IDs.
2609- func testCustomChannelsLiquidtyEdgeCasesCore (ctx context.Context ,
2610+ func testCustomChannelsLiquidityEdgeCasesCore (ctx context.Context ,
26102611 net * NetworkHarness , t * harnessTest , groupMode bool ) {
26112612
26122613 lndArgs := slices .Clone (lndArgsTemplate )
@@ -3104,6 +3105,69 @@ func testCustomChannelsLiquidtyEdgeCasesCore(ctx context.Context,
31043105 )
31053106
31063107 logBalance (t .t , nodes , assetID , "after small manual rfq" )
3108+
3109+ // Edge case: Fabia creates an invoice which Erin cannot satisfy with
3110+ // his side of asset liquidity. This tests that Erin will not try to
3111+ // add an HTLC with more asset units than what his local balance is. To
3112+ // validate that the channel is still healthy, we follow up with a
3113+ // smaller invoice payment which is meant to succeed.
3114+
3115+ // We now create a hodl invoice on Fabia, for 125k assets.
3116+ hodlInv = createAssetHodlInvoice (t .t , erin , fabia , 125_000 , assetID )
3117+
3118+ htlcStream , err := erin .RouterClient .SubscribeHtlcEvents (
3119+ ctx , & routerrpc.SubscribeHtlcEventsRequest {},
3120+ )
3121+ require .NoError (t .t , err )
3122+
3123+ // Charlie tries to pay, this is not meant to succeed, as Erin does not
3124+ // have enough assets to forward to Fabia.
3125+ payInvoiceWithAssets (
3126+ t .t , charlie , dave , hodlInv .payReq , assetID ,
3127+ withFailure (lnrpc .Payment_IN_FLIGHT , failureNone ),
3128+ )
3129+
3130+ // Let's check that at least 2 HTLCs were added on the Erin->Fabia link,
3131+ // which means that Erin would have an extra incoming HTLC for each
3132+ // outgoing one. So we expect a minimum of 4 HTLCs present on Erin.
3133+ assertMinNumHtlcs (t .t , erin , 4 )
3134+
3135+ // We also want to make sure that at least one failure occurred that
3136+ // hinted at the problem (not enough assets to forward).
3137+ assertHtlcEvents (
3138+ t .t , htlcStream , withNumEvents (1 ),
3139+ withLinkFailure (routerrpc .FailureDetail_INSUFFICIENT_BALANCE ),
3140+ )
3141+
3142+ logBalance (t .t , nodes , assetID , "with min 4 present HTLCs" )
3143+
3144+ // Now Fabia cancels the invoice, this is meant to cancel back any
3145+ // locked in HTLCs and reset Erin's local balance back to its original
3146+ // value.
3147+ payHash = hodlInv .preimage .Hash ()
3148+ _ , err = fabia .InvoicesClient .CancelInvoice (
3149+ ctx , & invoicesrpc.CancelInvoiceMsg {
3150+ PaymentHash : payHash [:],
3151+ },
3152+ )
3153+ require .NoError (t .t , err )
3154+
3155+ // Let's assert that Erin cancelled all his HTLCs.
3156+ assertNumHtlcs (t .t , erin , 0 )
3157+
3158+ logBalance (t .t , nodes , assetID , "after hodl cancel & 0 present HTLCs" )
3159+
3160+ // Now let's create a smaller invoice and pay it, to validate that the
3161+ // channel is still healthy.
3162+ invoiceResp = createAssetInvoice (
3163+ t .t , erin , fabia , 50_000 , assetID ,
3164+ )
3165+
3166+ payInvoiceWithAssets (
3167+ t .t , charlie , dave , invoiceResp .PaymentRequest , assetID ,
3168+ )
3169+
3170+ logBalance (t .t , nodes , assetID , "after safe asset htlc failure" )
31073171}
31083172
31093173// testCustomChannelsLiquidityEdgeCases is a test that runs through some
@@ -3113,7 +3177,7 @@ func testCustomChannelsLiquidityEdgeCases(ctx context.Context,
31133177
31143178 // Run liquidity edge cases and only use single asset IDs for invoices
31153179 // and payments.
3116- testCustomChannelsLiquidtyEdgeCasesCore (ctx , net , t , false )
3180+ testCustomChannelsLiquidityEdgeCasesCore (ctx , net , t , false )
31173181}
31183182
31193183// testCustomChannelsLiquidityEdgeCasesGroup is a test that runs through some
@@ -3123,7 +3187,7 @@ func testCustomChannelsLiquidityEdgeCasesGroup(ctx context.Context,
31233187
31243188 // Run liquidity edge cases and only use group keys for invoices and
31253189 // payments.
3126- testCustomChannelsLiquidtyEdgeCasesCore (ctx , net , t , true )
3190+ testCustomChannelsLiquidityEdgeCasesCore (ctx , net , t , true )
31273191}
31283192
31293193// testCustomChannelsStrictForwarding is a test that tests the strict forwarding
0 commit comments