@@ -2745,6 +2745,160 @@ func testCustomChannelsLiquidityEdgeCasesGroup(ctx context.Context,
27452745 testCustomChannelsLiquidtyEdgeCasesCore (ctx , net , t , true )
27462746}
27472747
2748+ // testCustomChannelsMultiRFQReceive tests that a node creating an invoice with
2749+ // multiple RFQ quotes can actually guide the payer into using multiple private
2750+ // taproot asset channels to pay the invoice.
2751+ func testCustomChannelsMultiRFQReceive (ctx context.Context , net * NetworkHarness ,
2752+ t * harnessTest ) {
2753+
2754+ lndArgs := slices .Clone (lndArgsTemplate )
2755+ litdArgs := slices .Clone (litdArgsTemplate )
2756+
2757+ // Explicitly set the proof courier as Zane (now has no other role
2758+ // other than proof shuffling), otherwise a hashmail courier will be
2759+ // used. For the funding transaction, we're just posting it and don't
2760+ // expect a true receiver.
2761+ zane , err := net .NewNode (
2762+ t .t , "Zane" , lndArgs , false , true , litdArgs ... ,
2763+ )
2764+ require .NoError (t .t , err )
2765+
2766+ litdArgs = append (litdArgs , fmt .Sprintf (
2767+ "--taproot-assets.proofcourieraddr=%s://%s" ,
2768+ proof .UniverseRpcCourierType , zane .Cfg .LitAddr (),
2769+ ))
2770+
2771+ charlie , err := net .NewNode (
2772+ t .t , "Charlie" , lndArgs , false , true , litdArgs ... ,
2773+ )
2774+ require .NoError (t .t , err )
2775+
2776+ dave , err := net .NewNode (t .t , "Dave" , lndArgs , false , true , litdArgs ... )
2777+ require .NoError (t .t , err )
2778+ erin , err := net .NewNode (t .t , "Erin" , lndArgs , false , true , litdArgs ... )
2779+ require .NoError (t .t , err )
2780+ fabia , err := net .NewNode (
2781+ t .t , "Fabia" , lndArgs , false , true , litdArgs ... ,
2782+ )
2783+ require .NoError (t .t , err )
2784+ yara , err := net .NewNode (
2785+ t .t , "Yara" , lndArgs , false , true , litdArgs ... ,
2786+ )
2787+ require .NoError (t .t , err )
2788+
2789+ nodes := []* HarnessNode {charlie , dave , erin , fabia , yara }
2790+ connectAllNodes (t .t , net , nodes )
2791+ fundAllNodes (t .t , net , nodes )
2792+
2793+ // The topology we are going for looks like the following:
2794+ //
2795+ // /---[sats]--> Erin --[assets]--\
2796+ // / \
2797+ // / \
2798+ // Charlie -----[sats]--> Dave --[assets]---->Fabia
2799+ // \ /
2800+ // \ /
2801+ // \---[sats]--> Yara --[assets]--/
2802+ //
2803+
2804+ // Let's open the normal sats channels between Charlie and the routing
2805+ // peers.
2806+ _ = openChannelAndAssert (
2807+ t , net , charlie , erin , lntest.OpenChannelParams {
2808+ Amt : 10_000_000 ,
2809+ SatPerVByte : 5 ,
2810+ },
2811+ )
2812+
2813+ _ = openChannelAndAssert (
2814+ t , net , charlie , dave , lntest.OpenChannelParams {
2815+ Amt : 10_000_000 ,
2816+ SatPerVByte : 5 ,
2817+ },
2818+ )
2819+
2820+ _ = openChannelAndAssert (
2821+ t , net , charlie , yara , lntest.OpenChannelParams {
2822+ Amt : 10_000_000 ,
2823+ SatPerVByte : 5 ,
2824+ },
2825+ )
2826+
2827+ // Let's create the tap clients.
2828+ universeTap := newTapClient (t .t , zane )
2829+ charlieTap := newTapClient (t .t , charlie )
2830+ daveTap := newTapClient (t .t , dave )
2831+ erinTap := newTapClient (t .t , erin )
2832+ fabiaTap := newTapClient (t .t , fabia )
2833+ yaraTap := newTapClient (t .t , yara )
2834+
2835+ assetReq := itest .CopyRequest (& mintrpc.MintAssetRequest {
2836+ Asset : itestAsset ,
2837+ })
2838+
2839+ assetReq .Asset .NewGroupedAsset = true
2840+
2841+ // Mint an asset on Charlie and sync all nodes to Charlie as the
2842+ // universe.
2843+ mintedAssets := itest .MintAssetsConfirmBatch (
2844+ t .t , t .lndHarness .Miner .Client , charlieTap ,
2845+ []* mintrpc.MintAssetRequest {assetReq },
2846+ )
2847+ cents := mintedAssets [0 ]
2848+ assetID := cents .AssetGenesis .AssetId
2849+ groupID := cents .GetAssetGroup ().GetTweakedGroupKey ()
2850+
2851+ syncUniverses (t .t , charlieTap , dave , erin , fabia , yara )
2852+
2853+ createTestMultiRFQAssetNetwork (
2854+ t , net , charlieTap , daveTap , erinTap , fabiaTap , yaraTap ,
2855+ universeTap , cents , 10_000 , 10_000 , 10_000 ,
2856+ )
2857+
2858+ logBalance (t .t , nodes , assetID , "before multi-rfq receive" )
2859+
2860+ hodlInv := createAssetHodlInvoice (t .t , nil , fabia , 20_000 , assetID )
2861+
2862+ payInvoiceWithSatoshi (
2863+ t .t , charlie , & lnrpc.AddInvoiceResponse {
2864+ PaymentRequest : hodlInv .payReq ,
2865+ },
2866+ withGroupKey (groupID ),
2867+ withFailure (lnrpc .Payment_IN_FLIGHT , failureNone ),
2868+ )
2869+
2870+ logBalance (t .t , nodes , assetID , "after inflight multi-rfq" )
2871+
2872+ // TODO: assert minNumHtlcs after rebase
2873+
2874+ // Now let's cancel the invoice and assert that all inbound channels
2875+ // have cleared their HTLCs.
2876+ payHash := hodlInv .preimage .Hash ()
2877+ _ , err = fabia .InvoicesClient .CancelInvoice (
2878+ ctx , & invoicesrpc.CancelInvoiceMsg {
2879+ PaymentHash : payHash [:],
2880+ },
2881+ )
2882+ require .NoError (t .t , err )
2883+
2884+ assertNumHtlcs (t .t , dave , 0 )
2885+ assertNumHtlcs (t .t , erin , 0 )
2886+ assertNumHtlcs (t .t , yara , 0 )
2887+
2888+ logBalance (t .t , nodes , assetID , "after cancelled hodl" )
2889+
2890+ // Now let's create a normal invoice that will be settled once all the
2891+ // HTLCs have been received. This is only possible because the payer
2892+ // uses multiple bolt11 hop hints to reach the destination.
2893+ invoiceResp := createAssetInvoice (t .t , nil , fabia , 15_000 , assetID )
2894+
2895+ payInvoiceWithSatoshi (
2896+ t .t , charlie , invoiceResp , withGroupKey (groupID ),
2897+ )
2898+
2899+ logBalance (t .t , nodes , assetID , "after multi-rfq receive" )
2900+ }
2901+
27482902// testCustomChannelsStrictForwarding is a test that tests the strict forwarding
27492903// behavior of a node when it comes to paying asset invoices with assets and
27502904// BTC invoices with satoshis.
0 commit comments