@@ -2867,6 +2867,122 @@ func testCustomChannelsLiquidityEdgeCasesGroup(ctx context.Context,
28672867 testCustomChannelsLiquidityEdgeCasesCore (ctx , net , t , true )
28682868}
28692869
2870+ // testCustomChannelsMultiRFQReceive tests that a node creating an invoice with
2871+ // multiple RFQ quotes can actually guide the payer into using multiple private
2872+ // taproot asset channels to pay the invoice.
2873+ func testCustomChannelsMultiRFQReceive (ctx context.Context , net * NetworkHarness ,
2874+ t * harnessTest ) {
2875+
2876+ lndArgs := slices .Clone (lndArgsTemplate )
2877+ litdArgs := slices .Clone (litdArgsTemplate )
2878+
2879+ charlie , err := net .NewNode (
2880+ t .t , "Charlie" , lndArgs , false , true , litdArgs ... ,
2881+ )
2882+ require .NoError (t .t , err )
2883+
2884+ litdArgs = append (litdArgs , fmt .Sprintf (
2885+ "--taproot-assets.proofcourieraddr=%s://%s" ,
2886+ proof .UniverseRpcCourierType , charlie .Cfg .LitAddr (),
2887+ ))
2888+
2889+ dave , err := net .NewNode (t .t , "Dave" , lndArgs , false , true , litdArgs ... )
2890+ require .NoError (t .t , err )
2891+ erin , err := net .NewNode (t .t , "Erin" , lndArgs , false , true , litdArgs ... )
2892+ require .NoError (t .t , err )
2893+ fabia , err := net .NewNode (
2894+ t .t , "Fabia" , lndArgs , false , true , litdArgs ... ,
2895+ )
2896+ require .NoError (t .t , err )
2897+ yara , err := net .NewNode (
2898+ t .t , "Yara" , lndArgs , false , true , litdArgs ... ,
2899+ )
2900+ require .NoError (t .t , err )
2901+
2902+ nodes := []* HarnessNode {charlie , dave , erin , fabia , yara }
2903+ connectAllNodes (t .t , net , nodes )
2904+ fundAllNodes (t .t , net , nodes )
2905+
2906+ // Let's create the tap clients.
2907+ charlieTap := newTapClient (t .t , charlie )
2908+ daveTap := newTapClient (t .t , dave )
2909+ erinTap := newTapClient (t .t , erin )
2910+ fabiaTap := newTapClient (t .t , fabia )
2911+ yaraTap := newTapClient (t .t , yara )
2912+
2913+ assetReq := itest .CopyRequest (& mintrpc.MintAssetRequest {
2914+ Asset : itestAsset ,
2915+ })
2916+
2917+ assetReq .Asset .NewGroupedAsset = true
2918+
2919+ // Mint an asset on Charlie and sync all nodes to Charlie as the
2920+ // universe.
2921+ mintedAssets := itest .MintAssetsConfirmBatch (
2922+ t .t , t .lndHarness .Miner .Client , charlieTap ,
2923+ []* mintrpc.MintAssetRequest {assetReq },
2924+ )
2925+ cents := mintedAssets [0 ]
2926+ assetID := cents .AssetGenesis .AssetId
2927+ groupID := cents .GetAssetGroup ().GetTweakedGroupKey ()
2928+
2929+ syncUniverses (t .t , charlieTap , dave , erin , fabia , yara )
2930+
2931+ createTestMultiRFQAssetNetwork (
2932+ t , net , charlie , dave , erin , fabia , yara , charlieTap , daveTap ,
2933+ erinTap , fabiaTap , yaraTap , charlieTap , cents , 10_000 , 10_000 ,
2934+ 10_000 ,
2935+ )
2936+
2937+ logBalance (t .t , nodes , assetID , "before multi-rfq receive" )
2938+
2939+ hodlInv := createAssetHodlInvoice (t .t , nil , fabia , 20_000 , assetID )
2940+
2941+ payInvoiceWithSatoshi (
2942+ t .t , charlie , & lnrpc.AddInvoiceResponse {
2943+ PaymentRequest : hodlInv .payReq ,
2944+ },
2945+ withGroupKey (groupID ),
2946+ withFailure (lnrpc .Payment_IN_FLIGHT , failureNone ),
2947+ )
2948+
2949+ logBalance (t .t , nodes , assetID , "after inflight multi-rfq" )
2950+
2951+ // Assert that some HTLCs are present from Fabia's point of view.
2952+ assertMinNumHtlcs (t .t , fabia , 1 )
2953+
2954+ // Assert that Charlie also has at least one outgoing HTLC as a sanity
2955+ // check.
2956+ assertMinNumHtlcs (t .t , charlie , 1 )
2957+
2958+ // Now let's cancel the invoice and assert that all inbound channels
2959+ // have cleared their HTLCs.
2960+ payHash := hodlInv .preimage .Hash ()
2961+ _ , err = fabia .InvoicesClient .CancelInvoice (
2962+ ctx , & invoicesrpc.CancelInvoiceMsg {
2963+ PaymentHash : payHash [:],
2964+ },
2965+ )
2966+ require .NoError (t .t , err )
2967+
2968+ assertNumHtlcs (t .t , dave , 0 )
2969+ assertNumHtlcs (t .t , erin , 0 )
2970+ assertNumHtlcs (t .t , yara , 0 )
2971+
2972+ logBalance (t .t , nodes , assetID , "after cancelled hodl" )
2973+
2974+ // Now let's create a normal invoice that will be settled once all the
2975+ // HTLCs have been received. This is only possible because the payer
2976+ // uses multiple bolt11 hop hints to reach the destination.
2977+ invoiceResp := createAssetInvoice (t .t , nil , fabia , 15_000 , assetID )
2978+
2979+ payInvoiceWithSatoshi (
2980+ t .t , charlie , invoiceResp , withGroupKey (groupID ),
2981+ )
2982+
2983+ logBalance (t .t , nodes , assetID , "after multi-rfq receive" )
2984+ }
2985+
28702986// testCustomChannelsStrictForwarding is a test that tests the strict forwarding
28712987// behavior of a node when it comes to paying asset invoices with assets and
28722988// BTC invoices with satoshis.
0 commit comments