From 4b45384e8414640d3957c57e928791177f4f816f Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Mon, 16 Jun 2025 15:19:43 +0200 Subject: [PATCH 1/4] mod: update tapd to v0.6.0 final --- go.mod | 4 ++-- go.sum | 8 ++++---- litrpc/go.mod | 2 +- litrpc/go.sum | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index c0a0c05c5..a03bbdba4 100644 --- a/go.mod +++ b/go.mod @@ -32,8 +32,8 @@ require ( github.com/lightninglabs/pool v0.6.6-beta github.com/lightninglabs/pool/auctioneerrpc v1.1.3 github.com/lightninglabs/pool/poolrpc v1.0.1 - github.com/lightninglabs/taproot-assets v0.6.0-rc3 - github.com/lightninglabs/taproot-assets/taprpc v1.0.6 + github.com/lightninglabs/taproot-assets v0.6.0 + github.com/lightninglabs/taproot-assets/taprpc v1.0.7 github.com/lightningnetwork/lnd v0.19.1-beta.rc1 github.com/lightningnetwork/lnd/cert v1.2.2 github.com/lightningnetwork/lnd/clock v1.1.1 diff --git a/go.sum b/go.sum index 36adbb9e0..c5587ec8a 100644 --- a/go.sum +++ b/go.sum @@ -1172,10 +1172,10 @@ github.com/lightninglabs/pool/poolrpc v1.0.1 h1:XbNx28TYwEj/PVsnnF9TnveVCMCYfS1v github.com/lightninglabs/pool/poolrpc v1.0.1/go.mod h1:836icifg/SBnZbiae0v3jeRRzCrT6LWo32SqCS/JiGk= github.com/lightninglabs/protobuf-go-hex-display v1.34.2-hex-display h1:w7FM5LH9Z6CpKxl13mS48idsu6F+cEZf0lkyiV+Dq9g= github.com/lightninglabs/protobuf-go-hex-display v1.34.2-hex-display/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= -github.com/lightninglabs/taproot-assets v0.6.0-rc3 h1:LLHmxeIcpiVcWxGL8DwZxn6LYjeowwwDbOSEEl1EdBA= -github.com/lightninglabs/taproot-assets v0.6.0-rc3/go.mod h1:38uM/4StASo1coMGPEab2vHPhfOjoQj0zCMgzPtNCgE= -github.com/lightninglabs/taproot-assets/taprpc v1.0.6 h1:h8tf4y7U5/3A9WNAs7HBTL8Vhgk/FT2JP2NldpwTaHE= -github.com/lightninglabs/taproot-assets/taprpc v1.0.6/go.mod h1:vOM2Ap2wYhEZjiJU7bNNg+e5tDxkvRAuyXwf/KQ4tgo= +github.com/lightninglabs/taproot-assets v0.6.0 h1:nHloX+QR2PbUmogry1T+LiYh1TWBoFnTMHOy4Hyq1VM= +github.com/lightninglabs/taproot-assets v0.6.0/go.mod h1:CkK0drLPo5M6ib9YRE3lD+znOfe0Oxh6zMvGN1SJXDo= +github.com/lightninglabs/taproot-assets/taprpc v1.0.7 h1:yUG9vdpajiU0gp4wDkTPz/6BI8Vr52OM2paahlVrAys= +github.com/lightninglabs/taproot-assets/taprpc v1.0.7/go.mod h1:vOM2Ap2wYhEZjiJU7bNNg+e5tDxkvRAuyXwf/KQ4tgo= github.com/lightningnetwork/lightning-onion v1.2.1-0.20240712235311-98bd56499dfb h1:yfM05S8DXKhuCBp5qSMZdtSwvJ+GFzl94KbXMNB1JDY= github.com/lightningnetwork/lightning-onion v1.2.1-0.20240712235311-98bd56499dfb/go.mod h1:c0kvRShutpj3l6B9WtTsNTBUtjSmjZXbJd9ZBRQOSKI= github.com/lightningnetwork/lnd v0.19.1-beta.rc1 h1:VV7xpS1g7OpDhlGYIa50Ac4I7TDZhvHjZ2Mmf+L4a7Y= diff --git a/litrpc/go.mod b/litrpc/go.mod index 3379f2e28..6eb4bd137 100644 --- a/litrpc/go.mod +++ b/litrpc/go.mod @@ -7,7 +7,7 @@ require ( github.com/lightninglabs/faraday/frdrpc v1.0.0 github.com/lightninglabs/loop/looprpc v1.0.0 github.com/lightninglabs/pool/poolrpc v1.0.0 - github.com/lightninglabs/taproot-assets/taprpc v1.0.5-0.20250526115916-1ac1deab2f9b + github.com/lightninglabs/taproot-assets/taprpc v1.0.7 github.com/lightningnetwork/lnd v0.19.0-beta google.golang.org/grpc v1.65.0 google.golang.org/protobuf v1.34.2 diff --git a/litrpc/go.sum b/litrpc/go.sum index 50616015e..4c06718cc 100644 --- a/litrpc/go.sum +++ b/litrpc/go.sum @@ -1102,8 +1102,8 @@ github.com/lightninglabs/pool/poolrpc v1.0.0 h1:vvosrgNx9WXF4mcHGqLjZOW8wNM0q+BL github.com/lightninglabs/pool/poolrpc v1.0.0/go.mod h1:ZqpEpBFRMMBAerMmilEjh27tqauSXDwLaLR0O3jvmMA= github.com/lightninglabs/protobuf-go-hex-display v1.34.2-hex-display h1:w7FM5LH9Z6CpKxl13mS48idsu6F+cEZf0lkyiV+Dq9g= github.com/lightninglabs/protobuf-go-hex-display v1.34.2-hex-display/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= -github.com/lightninglabs/taproot-assets/taprpc v1.0.5-0.20250526115916-1ac1deab2f9b h1:XmIJhYwUZ75BiZPXhsutwlgTin35QSjn+KhYbuPtHkQ= -github.com/lightninglabs/taproot-assets/taprpc v1.0.5-0.20250526115916-1ac1deab2f9b/go.mod h1:vOM2Ap2wYhEZjiJU7bNNg+e5tDxkvRAuyXwf/KQ4tgo= +github.com/lightninglabs/taproot-assets/taprpc v1.0.7 h1:yUG9vdpajiU0gp4wDkTPz/6BI8Vr52OM2paahlVrAys= +github.com/lightninglabs/taproot-assets/taprpc v1.0.7/go.mod h1:vOM2Ap2wYhEZjiJU7bNNg+e5tDxkvRAuyXwf/KQ4tgo= github.com/lightningnetwork/lightning-onion v1.2.1-0.20240712235311-98bd56499dfb h1:yfM05S8DXKhuCBp5qSMZdtSwvJ+GFzl94KbXMNB1JDY= github.com/lightningnetwork/lightning-onion v1.2.1-0.20240712235311-98bd56499dfb/go.mod h1:c0kvRShutpj3l6B9WtTsNTBUtjSmjZXbJd9ZBRQOSKI= github.com/lightningnetwork/lnd v0.19.0-beta h1:/8i2UdARiEpI2iAmPoSDcwZSSEuWqXyfsMxz/mLGbdw= From fe9a36ceeea0379dea7db5f3af76eb15ee1f1114 Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Mon, 16 Jun 2025 15:20:09 +0200 Subject: [PATCH 2/4] itest: test single sat keysend payment with no asset balance Tests an edge case that previously lead to a force close due to the following error: unable to sort commitment transaction: output and allocation size mismatch with error Having a below-dust satoshi balance is only allowed when there is no asset balance. But since such a dust output isn't materialized on-chain, tapd needs to filter it out correctly and not create an allocation. --- itest/assets_test.go | 23 ++++++++++++++++++++- itest/litd_custom_channels_test.go | 33 +++++++++++++++++++++++++++++- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/itest/assets_test.go b/itest/assets_test.go index b6786878f..e6de75fc9 100644 --- a/itest/assets_test.go +++ b/itest/assets_test.go @@ -1364,7 +1364,12 @@ func sendAssetKeySendPayment(t *testing.T, src, dst *HarnessNode, amt uint64, } func sendKeySendPayment(t *testing.T, src, dst *HarnessNode, - amt btcutil.Amount) { + amt btcutil.Amount, opts ...payOpt) { + + cfg := defaultPayConfig() + for _, opt := range opts { + opt(cfg) + } ctxb := context.Background() ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout) @@ -1382,12 +1387,21 @@ func sendKeySendPayment(t *testing.T, src, dst *HarnessNode, customRecords := make(map[uint64][]byte) customRecords[record.KeySendType] = preimage[:] + for key, value := range cfg.destCustomRecords { + customRecords[key] = value + } + req := &routerrpc.SendPaymentRequest{ Dest: dst.PubKey[:], Amt: int64(amt), DestCustomRecords: customRecords, PaymentHash: hash[:], TimeoutSeconds: int32(PaymentTimeout.Seconds()), + FeeLimitMsat: 1_000_000, + MaxParts: cfg.maxShards, + OutgoingChanIds: cfg.outgoingChanIDs, + AllowSelfPayment: cfg.allowSelfPayment, + RouteHints: cfg.routeHints, } stream, err := src.RouterClient.SendPaymentV2(ctxt, req) @@ -1548,6 +1562,7 @@ type payConfig struct { groupKey []byte outgoingChanIDs []uint64 allowSelfPayment bool + routeHints []*lnrpc.RouteHint } func defaultPayConfig() *payConfig { @@ -1631,6 +1646,12 @@ func withAllowSelfPayment() payOpt { } } +func withPayRouteHints(hints []*lnrpc.RouteHint) payOpt { + return func(c *payConfig) { + c.routeHints = hints + } +} + func payInvoiceWithAssets(t *testing.T, payer, rfqPeer *HarnessNode, payReq string, assetID []byte, opts ...payOpt) (uint64, rfqmath.BigIntFixedPoint) { diff --git a/itest/litd_custom_channels_test.go b/itest/litd_custom_channels_test.go index f6b746fa7..ac1f2f554 100644 --- a/itest/litd_custom_channels_test.go +++ b/itest/litd_custom_channels_test.go @@ -2389,7 +2389,7 @@ func testCustomChannelsLiquidityEdgeCasesCore(ctx context.Context, ) charlieFundingAmount := cents.Amount - uint64(2*400_000) - _, _, _ = createTestAssetNetwork( + _, _, chanPointEF := createTestAssetNetwork( t, net, charlieTap, daveTap, erinTap, fabiaTap, yaraTap, universeTap, cents, 400_000, charlieFundingAmount, daveFundingAmount, erinFundingAmount, 0, @@ -2407,6 +2407,37 @@ func testCustomChannelsLiquidityEdgeCasesCore(ctx context.Context, logBalance(t.t, nodes, assetID, "initial") + // Edge case: We send a single satoshi keysend payment from Dave to + // Fabia. Which will make it so that Fabia's balance in the channel + // between Erin and her is 1 satoshi, which is below the dust limit. + // This is only allowed while Fabia doesn't have any assets on her side + // yet. + erinFabiaChan := fetchChannel(t.t, fabia, chanPointEF) + hinEF := &lnrpc.HopHint{ + NodeId: erin.PubKeyStr, + ChanId: erinFabiaChan.PeerScidAlias, + CltvExpiryDelta: 80, + FeeBaseMsat: 1000, + FeeProportionalMillionths: 1, + } + sendKeySendPayment( + t.t, dave, fabia, 1, withPayRouteHints([]*lnrpc.RouteHint{{ + HopHints: []*lnrpc.HopHint{hinEF}, + }}), + ) + logBalance(t.t, nodes, assetID, "after single sat keysend") + + // We make sure that a single sat keysend payment is not allowed when + // it carries assets. + sendAssetKeySendPayment( + t.t, erin, fabia, 123, assetID, fn.Some[int64](1), + withPayErrSubStr( + fmt.Sprintf("keysend payment satoshi amount must be "+ + "greater than or equal to %d satoshis", + rfqmath.DefaultOnChainHtlcSat), + ), + ) + // Normal case. // Send 50 assets from Charlie to Dave. sendAssetKeySendPayment( From b0e1d552d15ecbc23a77ab211d0fb63b782421a7 Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Mon, 16 Jun 2025 15:21:53 +0200 Subject: [PATCH 3/4] itest: add test case for policy in route hint This commit tests that the routing policy of the correct peer (the policy pointing toward the recipient of an invoice) is included in an asset invoice. --- itest/assets_test.go | 4 +-- itest/litd_custom_channels_test.go | 48 ++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/itest/assets_test.go b/itest/assets_test.go index e6de75fc9..1fb456dac 100644 --- a/itest/assets_test.go +++ b/itest/assets_test.go @@ -1397,7 +1397,7 @@ func sendKeySendPayment(t *testing.T, src, dst *HarnessNode, DestCustomRecords: customRecords, PaymentHash: hash[:], TimeoutSeconds: int32(PaymentTimeout.Seconds()), - FeeLimitMsat: 1_000_000, + FeeLimitMsat: int64(cfg.feeLimit), MaxParts: cfg.maxShards, OutgoingChanIds: cfg.outgoingChanIDs, AllowSelfPayment: cfg.allowSelfPayment, @@ -1477,7 +1477,7 @@ func payPayReqWithSatoshi(t *testing.T, payer *HarnessNode, payReq string, sendReq := &routerrpc.SendPaymentRequest{ PaymentRequest: payReq, TimeoutSeconds: int32(PaymentTimeout.Seconds()), - FeeLimitMsat: 1_000_000, + FeeLimitMsat: int64(cfg.feeLimit), MaxParts: cfg.maxShards, OutgoingChanIds: cfg.outgoingChanIDs, AllowSelfPayment: cfg.allowSelfPayment, diff --git a/itest/litd_custom_channels_test.go b/itest/litd_custom_channels_test.go index ac1f2f554..7a23314fb 100644 --- a/itest/litd_custom_channels_test.go +++ b/itest/litd_custom_channels_test.go @@ -2901,6 +2901,54 @@ func testCustomChannelsLiquidityEdgeCasesCore(ctx context.Context, ) logBalance(t.t, nodes, assetID, "after safe asset htlc failure") + + // Another test case: Make sure an asset invoice contains the correct + // channel policy. We expect it to be the policy for the direction from + // edge node to receiver node. To test this, we first set two different + // policies on the channel between Erin and Fabia. + resp, err := erin.UpdateChannelPolicy(ctx, &lnrpc.PolicyUpdateRequest{ + Scope: &lnrpc.PolicyUpdateRequest_ChanPoint{ + ChanPoint: chanPointEF, + }, + BaseFeeMsat: 31337, + FeeRatePpm: 443322, + TimeLockDelta: 19, + }) + require.NoError(t.t, err) + require.Empty(t.t, resp.FailedUpdates) + + resp, err = fabia.UpdateChannelPolicy(ctx, &lnrpc.PolicyUpdateRequest{ + Scope: &lnrpc.PolicyUpdateRequest_ChanPoint{ + ChanPoint: chanPointEF, + }, + BaseFeeMsat: 42069, + FeeRatePpm: 223344, + TimeLockDelta: 18, + }) + require.NoError(t.t, err) + require.Empty(t.t, resp.FailedUpdates) + + // We now create an invoice on Fabia and expect Erin's policy to be used + // in the invoice. + invoiceResp = createAssetInvoice(t.t, erin, fabia, 1_000, assetID) + req, err := erin.DecodePayReq(ctx, &lnrpc.PayReqString{ + PayReq: invoiceResp.PaymentRequest, + }) + require.NoError(t.t, err) + + require.Len(t.t, req.RouteHints, 1) + require.Len(t.t, req.RouteHints[0].HopHints, 1) + invoiceHint := req.RouteHints[0].HopHints[0] + require.Equal(t.t, erin.PubKeyStr, invoiceHint.NodeId) + require.EqualValues(t.t, 31337, invoiceHint.FeeBaseMsat) + require.EqualValues(t.t, 443322, invoiceHint.FeeProportionalMillionths) + require.EqualValues(t.t, 19, invoiceHint.CltvExpiryDelta) + + // Now we pay the invoice and expect the same policy with very expensive + // fees to be used. + payInvoiceWithSatoshi( + t.t, dave, invoiceResp, withFeeLimit(100_000_000), + ) } // testCustomChannelsLiquidityEdgeCases is a test that runs through some From 6c5f6b14be618971c0b8c57ec993cb45b75f5a1d Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Tue, 17 Jun 2025 18:41:00 +0200 Subject: [PATCH 4/4] docs: update release notes --- docs/release-notes/release-notes-0.15.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/release-notes/release-notes-0.15.0.md b/docs/release-notes/release-notes-0.15.0.md index e6308dd55..38a6ab518 100644 --- a/docs/release-notes/release-notes-0.15.0.md +++ b/docs/release-notes/release-notes-0.15.0.md @@ -95,7 +95,7 @@ ### Taproot Assets * Updated [`tapd` to - `v0.6.0-rc3`](https://github.com/lightninglabs/lightning-terminal/pull/1082). + `v0.6.0`](https://github.com/lightninglabs/lightning-terminal/pull/1089). * All Taproot Asset Channel related commands (`litcli ln ...`) can now [use a new `--group_key` flag to interact with grouped asset channels](https://github.com/lightninglabs/lightning-terminal/pull/1052).