diff --git a/itest/assets_test.go b/itest/assets_test.go index 1658df952..c59527dd5 100644 --- a/itest/assets_test.go +++ b/itest/assets_test.go @@ -33,6 +33,7 @@ import ( "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/lntest/rpc" "github.com/lightningnetwork/lnd/lntest/wait" @@ -924,6 +925,52 @@ func createAssetInvoice(t *testing.T, dstRfqPeer, dst *HarnessNode, return resp.InvoiceResult } +// assertInvoiceHtlcAssets makes sure the invoice with the given hash shows the +// individual HTLCs that arrived for it and that they show the correct asset +// amounts for the given ID when decoded. +func assertInvoiceHtlcAssets(t *testing.T, node *HarnessNode, + addedInvoice *lnrpc.AddInvoiceResponse, assetID []byte, + assetAmount uint64) { + + ctxb := context.Background() + ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout) + defer cancel() + + invoice, err := node.InvoicesClient.LookupInvoiceV2( + ctxt, &invoicesrpc.LookupInvoiceMsg{ + InvoiceRef: &invoicesrpc.LookupInvoiceMsg_PaymentAddr{ + PaymentAddr: addedInvoice.PaymentAddr, + }, + }, + ) + require.NoError(t, err) + require.NotEmpty(t, invoice.Htlcs) + + t.Logf("Asset invoice: %v", toProtoJSON(t, invoice)) + + targetID := hex.EncodeToString(assetID) + + var totalAssetAmount uint64 + for _, htlc := range invoice.Htlcs { + require.NotEmpty(t, htlc.CustomChannelData) + + jsonHtlc := &rfqmsg.JsonHtlc{} + err := json.Unmarshal(htlc.CustomChannelData, jsonHtlc) + require.NoError(t, err) + + for _, balance := range jsonHtlc.Balances { + if balance.AssetID != targetID { + continue + } + + totalAssetAmount += balance.Amount + } + } + + // Due to rounding we allow up to 1 unit of error. + require.InDelta(t, assetAmount, totalAssetAmount, 1) +} + // assertPaymentHtlcAssets makes sure the payment with the given hash shows the // individual HTLCs that arrived for it and that they show the correct asset // amounts for the given ID when decoded. diff --git a/itest/litd_custom_channels_test.go b/itest/litd_custom_channels_test.go index 903c35e37..c36594350 100644 --- a/itest/litd_custom_channels_test.go +++ b/itest/litd_custom_channels_test.go @@ -243,6 +243,16 @@ func testCustomChannelsLarge(_ context.Context, net *NetworkHarness, payInvoiceWithAssets(t.t, charlie, dave, invoiceResp3, assetID, false) logBalance(t.t, nodes, assetID, "after invoice 3") + // Make sure the invoice on the receiver side and the payment on the + // sender side show the individual HTLCs that arrived for it and that + // they show the correct asset amounts when decoded. + assertInvoiceHtlcAssets( + t.t, dave, invoiceResp3, assetID, largeInvoiceAmount, + ) + assertPaymentHtlcAssets( + t.t, charlie, invoiceResp3.RHash, assetID, largeInvoiceAmount, + ) + // We keysend the rest, so that all the balance is on Dave's side. charlieRemainingBalance := charlieFundingAmount - largeInvoiceAmount - fabiaInvoiceAssetAmount/2 @@ -422,6 +432,16 @@ func testCustomChannels(_ context.Context, net *NetworkHarness, payInvoiceWithAssets(t.t, dave, charlie, invoiceResp, assetID, true) logBalance(t.t, nodes, assetID, "after invoice back") + // Make sure the invoice on the receiver side and the payment on the + // sender side show the individual HTLCs that arrived for it and that + // they show the correct asset amounts when decoded. + assertInvoiceHtlcAssets( + t.t, charlie, invoiceResp, assetID, charlieInvoiceAmount, + ) + assertPaymentHtlcAssets( + t.t, dave, invoiceResp.RHash, assetID, charlieInvoiceAmount, + ) + charlieAssetBalance += charlieInvoiceAmount daveAssetBalance -= charlieInvoiceAmount @@ -897,6 +917,16 @@ func testCustomChannelsGroupedAsset(_ context.Context, net *NetworkHarness, payInvoiceWithAssets(t.t, charlie, dave, invoiceResp, assetID, true) logBalance(t.t, nodes, assetID, "after invoice") + // Make sure the invoice on the receiver side and the payment on the + // sender side show the individual HTLCs that arrived for it and that + // they show the correct asset amounts when decoded. + assertInvoiceHtlcAssets( + t.t, dave, invoiceResp, assetID, daveInvoiceAssetAmount, + ) + assertPaymentHtlcAssets( + t.t, charlie, invoiceResp.RHash, assetID, daveInvoiceAssetAmount, + ) + charlieAssetBalance -= daveInvoiceAssetAmount daveAssetBalance += daveInvoiceAssetAmount @@ -1876,19 +1906,30 @@ func testCustomChannelsLiquidityEdgeCases(_ context.Context, "invoice, multi-hop)") // Edge case: Big asset invoice paid by direct peer with assets. + const bigAssetAmount = 100_000 invoiceResp := createAssetInvoice( - t.t, charlie, dave, 100_000, assetID, + t.t, charlie, dave, bigAssetAmount, assetID, ) - payInvoiceWithAssets(t.t, charlie, dave, invoiceResp, assetID, false) logBalance(t.t, nodes, assetID, "after big asset payment (asset "+ "invoice, direct)") + // Make sure the invoice on the receiver side and the payment on the + // sender side show the individual HTLCs that arrived for it and that + // they show the correct asset amounts when decoded. + assertInvoiceHtlcAssets( + t.t, dave, invoiceResp, assetID, bigAssetAmount, + ) + assertPaymentHtlcAssets( + t.t, charlie, invoiceResp.RHash, assetID, bigAssetAmount, + ) + // Edge case: Big normal invoice, paid by direct channel peer with // assets. + const hugeAssetAmount = 1_000_000 _ = createAndPayNormalInvoice( - t.t, dave, charlie, charlie, 1_000_000, assetID, true, + t.t, dave, charlie, charlie, hugeAssetAmount, assetID, true, ) logBalance(t.t, nodes, assetID, "after big asset payment (btc "+ @@ -1896,7 +1937,7 @@ func testCustomChannelsLiquidityEdgeCases(_ context.Context, // Dave sends 200k assets and 2k sats to Yara. sendAssetKeySendPayment( - t.t, dave, yara, 200_000, assetID, + t.t, dave, yara, 2*bigAssetAmount, assetID, fn.None[int64](), lnrpc.Payment_SUCCEEDED, fn.None[lnrpc.PaymentFailureReason](), ) @@ -1909,7 +1950,7 @@ func testCustomChannelsLiquidityEdgeCases(_ context.Context, // channels, where the total asset value exceeds the btc capacity of the // channels. invoiceResp = createAssetInvoice( - t.t, dave, charlie, 100_000, assetID, + t.t, dave, charlie, bigAssetAmount, assetID, ) payInvoiceWithAssets(t.t, yara, dave, invoiceResp, assetID, false)