1
1
package itest
2
2
3
3
import (
4
+ "bytes"
4
5
"context"
5
6
"fmt"
6
7
"math"
@@ -18,12 +19,14 @@ import (
18
19
"github.com/lightninglabs/taproot-assets/tapchannel"
19
20
"github.com/lightninglabs/taproot-assets/taprpc"
20
21
"github.com/lightninglabs/taproot-assets/taprpc/mintrpc"
22
+ "github.com/lightninglabs/taproot-assets/taprpc/rfqrpc"
21
23
tchrpc "github.com/lightninglabs/taproot-assets/taprpc/tapchannelrpc"
22
24
"github.com/lightninglabs/taproot-assets/taprpc/universerpc"
23
25
"github.com/lightninglabs/taproot-assets/tapscript"
24
26
"github.com/lightningnetwork/lnd/fn"
25
27
"github.com/lightningnetwork/lnd/lnrpc"
26
28
"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
29
+ "github.com/lightningnetwork/lnd/lnrpc/routerrpc"
27
30
"github.com/lightningnetwork/lnd/lntest"
28
31
"github.com/lightningnetwork/lnd/lntest/port"
29
32
"github.com/lightningnetwork/lnd/lntest/wait"
@@ -1766,7 +1769,7 @@ func testCustomChannelsLiquidityEdgeCases(_ context.Context,
1766
1769
SatPerVByte : 5 ,
1767
1770
},
1768
1771
)
1769
- defer closeChannelAndAssert (t , net , dave , channelOp , false )
1772
+ defer closeChannelAndAssert (t , net , dave , channelOp , true )
1770
1773
1771
1774
// This is the only public channel, we need everyone to be aware of it.
1772
1775
assertChannelKnown (t .t , charlie , channelOp )
@@ -1974,10 +1977,11 @@ func testCustomChannelsLiquidityEdgeCases(_ context.Context,
1974
1977
logBalance (t .t , nodes , assetID , "after small payment (asset " +
1975
1978
"invoice, <354sats)" )
1976
1979
1977
- // Edge case: Now Charlie creates an asset invoice to be paid for by
1980
+ // Edge case: Now Dave creates an asset invoice to be paid for by
1978
1981
// Yara with satoshi. For the last hop we try to settle the invoice in
1979
- // satoshi, where we will check whether Charlie's strict forwarding
1980
- // works as expected.
1982
+ // satoshi, where we will check whether Dave's strict forwarding works
1983
+ // as expected. Charlie is only used as a dummy RFQ peer in this case,
1984
+ // Yara totally ignored the RFQ hint and pays agnostically with sats.
1981
1985
invoiceResp = createAssetInvoice (
1982
1986
t .t , charlie , dave , 1 , assetID ,
1983
1987
)
@@ -2000,6 +2004,91 @@ func testCustomChannelsLiquidityEdgeCases(_ context.Context,
2000
2004
2001
2005
logBalance (t .t , nodes , assetID , "after failed payment (asset " +
2002
2006
"invoice, strict forwarding)" )
2007
+
2008
+ // Edge case: Charlie negotiates a quote with Dave which has a low max
2009
+ // amount (~170k sats). Then Charlie creates an invoice with a total
2010
+ // amount slightly larger than the max allowed in the quote (200k sats).
2011
+ // Erin will try to pay that invoice with sats, in shards of max size
2012
+ // 80k sats. Dave will eventually stop forwarding HTLCs as the RFQ HTLC
2013
+ // tracking mechanism should stop them from being forwarded, as they
2014
+ // violate the maximum allowed amount of the quote.
2015
+
2016
+ // Charlie starts by negotiating the quote.
2017
+ res , err := charlieTap .RfqClient .AddAssetBuyOrder (
2018
+ ctxb , & rfqrpc.AddAssetBuyOrderRequest {
2019
+ AssetSpecifier : & rfqrpc.AssetSpecifier {
2020
+ Id : & rfqrpc.AssetSpecifier_AssetId {
2021
+ AssetId : assetID ,
2022
+ },
2023
+ },
2024
+ AssetMaxAmt : 10_000 ,
2025
+ Expiry : uint64 (time .Now ().Add (time .Hour ).Unix ()),
2026
+ PeerPubKey : dave .PubKey [:],
2027
+ TimeoutSeconds : 10 ,
2028
+ },
2029
+ )
2030
+ require .NoError (t .t , err )
2031
+
2032
+ quote , ok := res .Response .(* rfqrpc.AddAssetBuyOrderResponse_AcceptedQuote )
2033
+ require .True (t .t , ok )
2034
+
2035
+ // We now manually add the invoice in order to inject the above,
2036
+ // manually generated, quote.
2037
+ iResp , err := charlie .AddInvoice (ctxb , & lnrpc.Invoice {
2038
+ Memo : "" ,
2039
+ Value : 200_000 ,
2040
+ RPreimage : bytes .Repeat ([]byte {11 }, 32 ),
2041
+ CltvExpiry : 60 ,
2042
+ RouteHints : []* lnrpc.RouteHint {
2043
+ & lnrpc.RouteHint {
2044
+ HopHints : []* lnrpc.HopHint {
2045
+ & lnrpc.HopHint {
2046
+ NodeId : dave .PubKeyStr ,
2047
+ ChanId : quote .AcceptedQuote .Scid ,
2048
+ },
2049
+ },
2050
+ },
2051
+ },
2052
+ })
2053
+ require .NoError (t .t , err )
2054
+
2055
+ // Now Erin tries to pay the invoice. Since the multipart payment will
2056
+ // have some of its shards failing the pathfinding logic will keep going
2057
+ // and we won't see a payment failure but a timeout. If a final outcome
2058
+ // is not produced within a reasonable amount of time, we assume the
2059
+ // payment is still trying to find a route, therefore the HTLC rejection
2060
+ // works.
2061
+ timeoutChan = time .After (PaymentTimeout / 2 )
2062
+ done = make (chan bool , 1 )
2063
+
2064
+ ctxc , cancel := context .WithCancel (context .Background ())
2065
+
2066
+ //nolint:lll
2067
+ go func () {
2068
+ // payInvoiceWithSatoshi(t.t, erin, iResp, lnrpc.Payment_FAILED)
2069
+ sendReq := & routerrpc.SendPaymentRequest {
2070
+ PaymentRequest : iResp .PaymentRequest ,
2071
+ TimeoutSeconds : int32 (PaymentTimeout .Seconds ()),
2072
+ MaxShardSizeMsat : 80_000_000 ,
2073
+ FeeLimitMsat : 1_000_000 ,
2074
+ }
2075
+ stream , err := erin .RouterClient .SendPaymentV2 (ctxc , sendReq )
2076
+ if err == nil {
2077
+ _ , _ = getPaymentResult (stream )
2078
+ }
2079
+
2080
+ done <- true
2081
+ }()
2082
+
2083
+ select {
2084
+ case <- done :
2085
+ t .Fatalf ("Payment should not produce a final outcome" )
2086
+
2087
+ case <- timeoutChan :
2088
+ cancel ()
2089
+ }
2090
+
2091
+ logBalance (t .t , nodes , assetID , "after htlc track" )
2003
2092
}
2004
2093
2005
2094
// testCustomChannelsBalanceConsistency is a test that test the balance of nodes
0 commit comments