Skip to content

Commit

Permalink
itest: extend liquidity edge cases for rfq htlc tracking
Browse files Browse the repository at this point in the history
  • Loading branch information
GeorgeTsagk committed Nov 23, 2024
1 parent 4bde280 commit e0ab462
Showing 1 changed file with 93 additions and 4 deletions.
97 changes: 93 additions & 4 deletions itest/litd_custom_channels_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package itest

import (
"bytes"
"context"
"fmt"
"math"
Expand All @@ -18,12 +19,14 @@ import (
"github.com/lightninglabs/taproot-assets/tapchannel"
"github.com/lightninglabs/taproot-assets/taprpc"
"github.com/lightninglabs/taproot-assets/taprpc/mintrpc"
"github.com/lightninglabs/taproot-assets/taprpc/rfqrpc"
tchrpc "github.com/lightninglabs/taproot-assets/taprpc/tapchannelrpc"
"github.com/lightninglabs/taproot-assets/taprpc/universerpc"
"github.com/lightninglabs/taproot-assets/tapscript"
"github.com/lightningnetwork/lnd/fn"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
"github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntest/port"
Expand Down Expand Up @@ -1805,7 +1808,7 @@ func testCustomChannelsLiquidityEdgeCases(_ context.Context,
SatPerVByte: 5,
},
)
defer closeChannelAndAssert(t, net, dave, channelOp, false)
defer closeChannelAndAssert(t, net, dave, channelOp, true)

// This is the only public channel, we need everyone to be aware of it.
assertChannelKnown(t.t, charlie, channelOp)
Expand Down Expand Up @@ -2020,10 +2023,11 @@ func testCustomChannelsLiquidityEdgeCases(_ context.Context,
logBalance(t.t, nodes, assetID, "after small payment (asset "+
"invoice, <354sats)")

// Edge case: Now Charlie creates an asset invoice to be paid for by
// Edge case: Now Dave creates an asset invoice to be paid for by
// Yara with satoshi. For the last hop we try to settle the invoice in
// satoshi, where we will check whether Charlie's strict forwarding
// works as expected.
// satoshi, where we will check whether Dave's strict forwarding works
// as expected. Charlie is only used as a dummy RFQ peer in this case,
// Yara totally ignored the RFQ hint and pays agnostically with sats.
invoiceResp = createAssetInvoice(
t.t, charlie, dave, 1, assetID,
)
Expand All @@ -2046,6 +2050,91 @@ func testCustomChannelsLiquidityEdgeCases(_ context.Context,

logBalance(t.t, nodes, assetID, "after failed payment (asset "+
"invoice, strict forwarding)")

// Edge case: Charlie negotiates a quote with Dave which has a low max
// amount (~170k sats). Then Charlie creates an invoice with a total
// amount slightly larger than the max allowed in the quote (200k sats).
// Erin will try to pay that invoice with sats, in shards of max size
// 80k sats. Dave will eventually stop forwarding HTLCs as the RFQ HTLC
// tracking mechanism should stop them from being forwarded, as they
// violate the maximum allowed amount of the quote.

// Charlie starts by negotiating the quote.
res, err := charlieTap.RfqClient.AddAssetBuyOrder(
ctxb, &rfqrpc.AddAssetBuyOrderRequest{
AssetSpecifier: &rfqrpc.AssetSpecifier{
Id: &rfqrpc.AssetSpecifier_AssetId{
AssetId: assetID,
},
},
AssetMaxAmt: 10_000,
Expiry: uint64(time.Now().Add(time.Hour).Unix()),
PeerPubKey: dave.PubKey[:],
TimeoutSeconds: 10,
},
)
require.NoError(t.t, err)

quote, ok := res.Response.(*rfqrpc.AddAssetBuyOrderResponse_AcceptedQuote)
require.True(t.t, ok)

// We now manually add the invoice in order to inject the above,
// manually generated, quote.
iResp, err := charlie.AddInvoice(ctxb, &lnrpc.Invoice{
Memo: "",
Value: 200_000,
RPreimage: bytes.Repeat([]byte{11}, 32),
CltvExpiry: 60,
RouteHints: []*lnrpc.RouteHint{
&lnrpc.RouteHint{
HopHints: []*lnrpc.HopHint{
&lnrpc.HopHint{
NodeId: dave.PubKeyStr,
ChanId: quote.AcceptedQuote.Scid,
},
},
},
},
})
require.NoError(t.t, err)

// Now Erin tries to pay the invoice. Since the multipart payment will
// have some of its shards failing the pathfinding logic will keep going
// and we won't see a payment failure but a timeout. If a final outcome
// is not produced within a reasonable amount of time, we assume the
// payment is still trying to find a route, therefore the HTLC rejection
// works.
timeoutChan = time.After(PaymentTimeout / 2)
done = make(chan bool, 1)

ctxc, cancel := context.WithCancel(context.Background())

//nolint:lll
go func() {
// payInvoiceWithSatoshi(t.t, erin, iResp, lnrpc.Payment_FAILED)
sendReq := &routerrpc.SendPaymentRequest{
PaymentRequest: iResp.PaymentRequest,
TimeoutSeconds: int32(PaymentTimeout.Seconds()),
MaxShardSizeMsat: 80_000_000,
FeeLimitMsat: 1_000_000,
}
stream, err := erin.RouterClient.SendPaymentV2(ctxc, sendReq)
if err == nil {
_, _ = getPaymentResult(stream)
}

done <- true
}()

select {
case <-done:
t.Fatalf("Payment should not produce a final outcome")

case <-timeoutChan:
cancel()
}

logBalance(t.t, nodes, assetID, "after htlc track")
}

// testCustomChannelsBalanceConsistency is a test that test the balance of nodes
Expand Down

0 comments on commit e0ab462

Please sign in to comment.