@@ -2892,6 +2892,144 @@ func testCustomChannelsLiquidityEdgeCasesGroup(ctx context.Context,
2892
2892
testCustomChannelsLiquidityEdgeCasesCore (ctx , net , t , true )
2893
2893
}
2894
2894
2895
+ // testCustomChannelsMultiRFQReceive tests that a node creating an invoice with
2896
+ // multiple RFQ quotes can actually guide the payer into using multiple private
2897
+ // taproot asset channels to pay the invoice.
2898
+ func testCustomChannelsMultiRFQReceive (ctx context.Context , net * NetworkHarness ,
2899
+ t * harnessTest ) {
2900
+
2901
+ lndArgs := slices .Clone (lndArgsTemplate )
2902
+ litdArgs := slices .Clone (litdArgsTemplate )
2903
+
2904
+ charlie , err := net .NewNode (
2905
+ t .t , "Charlie" , lndArgs , false , true , litdArgs ... ,
2906
+ )
2907
+ require .NoError (t .t , err )
2908
+
2909
+ litdArgs = append (litdArgs , fmt .Sprintf (
2910
+ "--taproot-assets.proofcourieraddr=%s://%s" ,
2911
+ proof .UniverseRpcCourierType , charlie .Cfg .LitAddr (),
2912
+ ))
2913
+
2914
+ dave , err := net .NewNode (t .t , "Dave" , lndArgs , false , true , litdArgs ... )
2915
+ require .NoError (t .t , err )
2916
+ erin , err := net .NewNode (t .t , "Erin" , lndArgs , false , true , litdArgs ... )
2917
+ require .NoError (t .t , err )
2918
+ fabia , err := net .NewNode (
2919
+ t .t , "Fabia" , lndArgs , false , true , litdArgs ... ,
2920
+ )
2921
+ require .NoError (t .t , err )
2922
+ yara , err := net .NewNode (
2923
+ t .t , "Yara" , lndArgs , false , true , litdArgs ... ,
2924
+ )
2925
+ require .NoError (t .t , err )
2926
+
2927
+ nodes := []* HarnessNode {charlie , dave , erin , fabia , yara }
2928
+ connectAllNodes (t .t , net , nodes )
2929
+ fundAllNodes (t .t , net , nodes )
2930
+
2931
+ // Let's create the tap clients.
2932
+ charlieTap := newTapClient (t .t , charlie )
2933
+ daveTap := newTapClient (t .t , dave )
2934
+ erinTap := newTapClient (t .t , erin )
2935
+ fabiaTap := newTapClient (t .t , fabia )
2936
+ yaraTap := newTapClient (t .t , yara )
2937
+
2938
+ assetReq := itest .CopyRequest (& mintrpc.MintAssetRequest {
2939
+ Asset : itestAsset ,
2940
+ })
2941
+
2942
+ assetReq .Asset .NewGroupedAsset = true
2943
+
2944
+ // Mint an asset on Charlie and sync all nodes to Charlie as the
2945
+ // universe.
2946
+ mintedAssets := itest .MintAssetsConfirmBatch (
2947
+ t .t , t .lndHarness .Miner .Client , charlieTap ,
2948
+ []* mintrpc.MintAssetRequest {assetReq },
2949
+ )
2950
+ cents := mintedAssets [0 ]
2951
+ assetID := cents .AssetGenesis .AssetId
2952
+ groupID := cents .GetAssetGroup ().GetTweakedGroupKey ()
2953
+
2954
+ syncUniverses (t .t , charlieTap , dave , erin , fabia , yara )
2955
+
2956
+ multiRfqNodes := multiRfqNodes {
2957
+ charlie : itestNode {
2958
+ Lnd : charlie ,
2959
+ Tapd : charlieTap ,
2960
+ },
2961
+ dave : itestNode {
2962
+ Lnd : dave ,
2963
+ Tapd : daveTap ,
2964
+ },
2965
+ erin : itestNode {
2966
+ Lnd : erin ,
2967
+ Tapd : erinTap ,
2968
+ },
2969
+ fabia : itestNode {
2970
+ Lnd : fabia ,
2971
+ Tapd : fabiaTap ,
2972
+ },
2973
+ yara : itestNode {
2974
+ Lnd : yara ,
2975
+ Tapd : yaraTap ,
2976
+ },
2977
+ universeTap : charlieTap ,
2978
+ }
2979
+
2980
+ createTestMultiRFQAssetNetwork (
2981
+ t , net , multiRfqNodes , cents , 10_000 , 10_000 , 10_000 ,
2982
+ )
2983
+
2984
+ logBalance (t .t , nodes , assetID , "before multi-rfq receive" )
2985
+
2986
+ hodlInv := createAssetHodlInvoice (t .t , nil , fabia , 20_000 , assetID )
2987
+
2988
+ payInvoiceWithSatoshi (
2989
+ t .t , charlie , & lnrpc.AddInvoiceResponse {
2990
+ PaymentRequest : hodlInv .payReq ,
2991
+ },
2992
+ withGroupKey (groupID ),
2993
+ withFailure (lnrpc .Payment_IN_FLIGHT , failureNone ),
2994
+ )
2995
+
2996
+ logBalance (t .t , nodes , assetID , "after inflight multi-rfq" )
2997
+
2998
+ // Assert that some HTLCs are present from Fabia's point of view.
2999
+ assertMinNumHtlcs (t .t , fabia , 1 )
3000
+
3001
+ // Assert that Charlie also has at least one outgoing HTLC as a sanity
3002
+ // check.
3003
+ assertMinNumHtlcs (t .t , charlie , 1 )
3004
+
3005
+ // Now let's cancel the invoice and assert that all inbound channels
3006
+ // have cleared their HTLCs.
3007
+ payHash := hodlInv .preimage .Hash ()
3008
+ _ , err = fabia .InvoicesClient .CancelInvoice (
3009
+ ctx , & invoicesrpc.CancelInvoiceMsg {
3010
+ PaymentHash : payHash [:],
3011
+ },
3012
+ )
3013
+ require .NoError (t .t , err )
3014
+
3015
+ assertNumHtlcs (t .t , dave , 0 )
3016
+ assertNumHtlcs (t .t , erin , 0 )
3017
+ assertNumHtlcs (t .t , yara , 0 )
3018
+
3019
+ logBalance (t .t , nodes , assetID , "after cancelled hodl" )
3020
+
3021
+ // Now let's create a normal invoice that will be settled once all the
3022
+ // HTLCs have been received. This is only possible because the payer
3023
+ // uses multiple bolt11 hop hints to reach the destination.
3024
+ invoiceResp := createAssetInvoice (t .t , nil , fabia , 15_000 , assetID )
3025
+
3026
+ payInvoiceWithSatoshi (
3027
+ t .t , charlie , invoiceResp , withGroupKey (groupID ),
3028
+ )
3029
+
3030
+ logBalance (t .t , nodes , assetID , "after multi-rfq receive" )
3031
+ }
3032
+
2895
3033
// testCustomChannelsStrictForwarding is a test that tests the strict forwarding
2896
3034
// behavior of a node when it comes to paying asset invoices with assets and
2897
3035
// BTC invoices with satoshis.
0 commit comments