Skip to content

Commit 91bc1ac

Browse files
authored
Merge pull request #1097 from GeorgeTsagk/multi-rfq-send-itest
Multi rfq send itest
2 parents f3aba31 + 5cb0205 commit 91bc1ac

File tree

7 files changed

+269
-80
lines changed

7 files changed

+269
-80
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ GO_VERSION = 1.23.9
2828
# installed before running the integration tests which include backward
2929
# compatibility tests. The list of versions must be in sync with any version
3030
# used in the backwardCompat map in itest/litd_test_list_on_test.go.
31-
LITD_COMPAT_VERSIONS = v0.14.1-alpha
31+
LITD_COMPAT_VERSIONS = v0.14.1-alpha v0.15.0-alpha
3232

3333
LOOP_COMMIT := $(shell cat go.mod | \
3434
grep $(LOOP_PKG) | \

go.mod

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,18 @@ require (
2626
github.com/lightninglabs/lightning-terminal/litrpc v1.0.2
2727
github.com/lightninglabs/lightning-terminal/perms v1.0.1
2828
github.com/lightninglabs/lndclient v0.19.0-12
29-
github.com/lightninglabs/loop v0.31.2-beta.0.20250724051925-36c5d6cee7d3
29+
github.com/lightninglabs/loop v0.31.2-beta.0.20250730111713-3b0f6e84dc14
3030
github.com/lightninglabs/loop/looprpc v1.0.8
3131
github.com/lightninglabs/loop/swapserverrpc v1.0.15
3232
github.com/lightninglabs/pool v0.6.6-beta
3333
github.com/lightninglabs/pool/auctioneerrpc v1.1.3
3434
github.com/lightninglabs/pool/poolrpc v1.0.1
35-
github.com/lightninglabs/taproot-assets v0.6.1
36-
github.com/lightninglabs/taproot-assets/taprpc v1.0.10-0.20250725201706-0e736bb0d7b1
35+
github.com/lightninglabs/taproot-assets v0.6.1-0.20250729190616-3f323918a96e
36+
github.com/lightninglabs/taproot-assets/taprpc v1.0.10-0.20250729190616-3f323918a96e
3737
github.com/lightningnetwork/lnd v0.19.2-beta
3838
github.com/lightningnetwork/lnd/cert v1.2.2
3939
github.com/lightningnetwork/lnd/clock v1.1.1
40-
github.com/lightningnetwork/lnd/fn v1.2.3
40+
github.com/lightningnetwork/lnd/fn v1.2.5
4141
github.com/lightningnetwork/lnd/fn/v2 v2.0.8
4242
github.com/lightningnetwork/lnd/kvdb v1.4.16
4343
github.com/lightningnetwork/lnd/sqldb v1.0.11-0.20250623231731-45c15646c68b
@@ -247,5 +247,3 @@ replace google.golang.org/protobuf => github.com/lightninglabs/protobuf-go-hex-d
247247
// it is a replace in the tapd repository, it doesn't get propagated here
248248
// automatically, so we need to add it manually.
249249
replace github.com/golang-migrate/migrate/v4 => github.com/lightninglabs/migrate/v4 v4.18.2-9023d66a-fork-pr-2
250-
251-
replace github.com/lightninglabs/taproot-assets => github.com/lightninglabs/taproot-assets v0.6.1-0.20250725201706-0e736bb0d7b1

go.sum

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,8 +1152,8 @@ github.com/lightninglabs/lightning-node-connect/mailbox v1.0.1 h1:RWmohykp3n/DTM
11521152
github.com/lightninglabs/lightning-node-connect/mailbox v1.0.1/go.mod h1:NYtNexZE9gO1eOeegTxmIW9fqanl7eZ9cOrE9yewSAk=
11531153
github.com/lightninglabs/lndclient v0.19.0-12 h1:aSIKfnvnHKiyFWppUGHJG5fn8VoF5WG5Lx958ksLmqs=
11541154
github.com/lightninglabs/lndclient v0.19.0-12/go.mod h1:cicoJY1AwZuRVXGD8Knp50TRT7TGBmw1k37uPQsGQiw=
1155-
github.com/lightninglabs/loop v0.31.2-beta.0.20250724051925-36c5d6cee7d3 h1:N+p1pdmVG9STFZ0PIc+qzJ2einOyNzFy6KEjPmT7HAY=
1156-
github.com/lightninglabs/loop v0.31.2-beta.0.20250724051925-36c5d6cee7d3/go.mod h1:7DLIgIyg0Z9uQAjEUr0qNQ3v3IFPCDsJxIttHOxhcvA=
1155+
github.com/lightninglabs/loop v0.31.2-beta.0.20250730111713-3b0f6e84dc14 h1:PA/bTHYZ/leIoky3mFgbD4h9FV1lamzS+bw45GLd4l8=
1156+
github.com/lightninglabs/loop v0.31.2-beta.0.20250730111713-3b0f6e84dc14/go.mod h1:ukAfrXOf5OqpJORSYLjsyFzOGgIASyC2Qbstsl0ZvWw=
11571157
github.com/lightninglabs/loop/looprpc v1.0.8 h1:OFmJNLjem6fLuH1YUO+3G6QA1wmjAd0zyhvdHONOBDs=
11581158
github.com/lightninglabs/loop/looprpc v1.0.8/go.mod h1:c7WykKQZ3PspCMVvv2kr9o4l3bgJBEBVv0SOoBOjPOw=
11591159
github.com/lightninglabs/loop/swapserverrpc v1.0.15 h1:vEZBF65Lv0T7MPydCRxHSIlEJzHBkZ4I8FtSD6OJK88=
@@ -1172,10 +1172,10 @@ github.com/lightninglabs/pool/poolrpc v1.0.1 h1:XbNx28TYwEj/PVsnnF9TnveVCMCYfS1v
11721172
github.com/lightninglabs/pool/poolrpc v1.0.1/go.mod h1:836icifg/SBnZbiae0v3jeRRzCrT6LWo32SqCS/JiGk=
11731173
github.com/lightninglabs/protobuf-go-hex-display v1.34.2-hex-display h1:w7FM5LH9Z6CpKxl13mS48idsu6F+cEZf0lkyiV+Dq9g=
11741174
github.com/lightninglabs/protobuf-go-hex-display v1.34.2-hex-display/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
1175-
github.com/lightninglabs/taproot-assets v0.6.1-0.20250725201706-0e736bb0d7b1 h1:lm/PJTGwTPk7kRInRdGiUbaKqpNQlV+9OTXpBUiFb9E=
1176-
github.com/lightninglabs/taproot-assets v0.6.1-0.20250725201706-0e736bb0d7b1/go.mod h1:mIgx0p/GkMZeEjEm91vYQsH41YQBAgJl7TP6JcT+wgs=
1177-
github.com/lightninglabs/taproot-assets/taprpc v1.0.10-0.20250725201706-0e736bb0d7b1 h1:V9x07euSL3wR9JxPUOhrsAVmC6pg4o3y7N5GsHLVoP0=
1178-
github.com/lightninglabs/taproot-assets/taprpc v1.0.10-0.20250725201706-0e736bb0d7b1/go.mod h1:c8gTEcKEUoUPVChgZNwqTL1hss7UWa5FDeObr8WBzQk=
1175+
github.com/lightninglabs/taproot-assets v0.6.1-0.20250729190616-3f323918a96e h1:wlaM8dTlpCQ0uNj0TBskBDeNTTDessxiXiakYDB4RFo=
1176+
github.com/lightninglabs/taproot-assets v0.6.1-0.20250729190616-3f323918a96e/go.mod h1:mIgx0p/GkMZeEjEm91vYQsH41YQBAgJl7TP6JcT+wgs=
1177+
github.com/lightninglabs/taproot-assets/taprpc v1.0.10-0.20250729190616-3f323918a96e h1:MnXspinwkd6VhV8G9I+TdSak05UitfYyNBCQhTIIr0g=
1178+
github.com/lightninglabs/taproot-assets/taprpc v1.0.10-0.20250729190616-3f323918a96e/go.mod h1:c8gTEcKEUoUPVChgZNwqTL1hss7UWa5FDeObr8WBzQk=
11791179
github.com/lightningnetwork/lightning-onion v1.2.1-0.20240712235311-98bd56499dfb h1:yfM05S8DXKhuCBp5qSMZdtSwvJ+GFzl94KbXMNB1JDY=
11801180
github.com/lightningnetwork/lightning-onion v1.2.1-0.20240712235311-98bd56499dfb/go.mod h1:c0kvRShutpj3l6B9WtTsNTBUtjSmjZXbJd9ZBRQOSKI=
11811181
github.com/lightningnetwork/lnd v0.19.2-beta h1:3SKVrKYFY4IJLlrMf7cDzZcBeT+MxjI9Xy6YpY+EEX4=
@@ -1184,8 +1184,8 @@ github.com/lightningnetwork/lnd/cert v1.2.2 h1:71YK6hogeJtxSxw2teq3eGeuy4rHGKcFf
11841184
github.com/lightningnetwork/lnd/cert v1.2.2/go.mod h1:jQmFn/Ez4zhDgq2hnYSw8r35bqGVxViXhX6Cd7HXM6U=
11851185
github.com/lightningnetwork/lnd/clock v1.1.1 h1:OfR3/zcJd2RhH0RU+zX/77c0ZiOnIMsDIBjgjWdZgA0=
11861186
github.com/lightningnetwork/lnd/clock v1.1.1/go.mod h1:mGnAhPyjYZQJmebS7aevElXKTFDuO+uNFFfMXK1W8xQ=
1187-
github.com/lightningnetwork/lnd/fn v1.2.3 h1:Q1OrgNSgQynVheBNa16CsKVov1JI5N2AR6G07x9Mles=
1188-
github.com/lightningnetwork/lnd/fn v1.2.3/go.mod h1:SyFohpVrARPKH3XVAJZlXdVe+IwMYc4OMAvrDY32kw0=
1187+
github.com/lightningnetwork/lnd/fn v1.2.5 h1:pGMz0BDUxrhvOtShD4FIysdVy+ulfFAnFvTKjZO5Pp8=
1188+
github.com/lightningnetwork/lnd/fn v1.2.5/go.mod h1:SyFohpVrARPKH3XVAJZlXdVe+IwMYc4OMAvrDY32kw0=
11891189
github.com/lightningnetwork/lnd/fn/v2 v2.0.8 h1:r2SLz7gZYQPVc3IZhU82M66guz3Zk2oY+Rlj9QN5S3g=
11901190
github.com/lightningnetwork/lnd/fn/v2 v2.0.8/go.mod h1:TOzwrhjB/Azw1V7aa8t21ufcQmdsQOQMDtxVOQWNl8s=
11911191
github.com/lightningnetwork/lnd/healthcheck v1.2.6 h1:1sWhqr93GdkWy4+6U7JxBfcyZIE78MhIHTJZfPx7qqI=

itest/assets_test.go

Lines changed: 99 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -77,25 +77,32 @@ type itestNode struct {
7777
// multiRfqNodes contains all the itest nodes that are required to set up the
7878
// multi RFQ network topology.
7979
type multiRfqNodes struct {
80-
charlie, dave, erin, fabia, yara itestNode
81-
universeTap *tapClient
80+
charlie, dave, erin, fabia, yara, george itestNode
81+
universeTap *tapClient
8282
}
8383

8484
// createTestMultiRFQAssetNetwork creates a lightning network topology which
8585
// consists of both bitcoin and asset channels. It focuses on the property of
8686
// having multiple channels available on both the sender and receiver side.
87+
// The George node is using a way different oracle that provides asset rates
88+
// that fall outside of the configured tolerance bounds, leading to RFQ
89+
// negotiation failures.
8790
//
8891
// The topology we are going for looks like the following:
8992
//
90-
// /---[sats]--> Erin --[assets]--\
91-
// / \
92-
// / \
93+
// /---[sats]--> Erin --[assets]--\
94+
// / \
95+
// / \
96+
// / \
9397
//
94-
// Charlie -----[sats]--> Dave --[assets]---->Fabia
98+
// Charlie -----[sats]--> Dave --[assets]--> Fabia
9599
//
96-
// \ /
97-
// \ /
98-
// \---[sats]--> Yara --[assets]--/
100+
// \ / /
101+
// \ / /
102+
// \---[sats]--> Yara --[assets]-----/ /
103+
// \ /
104+
// \ /
105+
// \--[sats]-> George --[assets]-/
99106
func createTestMultiRFQAssetNetwork(t *harnessTest, net *NetworkHarness,
100107
nodes multiRfqNodes, mintedAsset *taprpc.Asset, assetSendAmount,
101108
fundingAmount uint64, pushSat int64) (*lnrpc.ChannelPoint,
@@ -106,6 +113,7 @@ func createTestMultiRFQAssetNetwork(t *harnessTest, net *NetworkHarness,
106113
erin, erinTap := nodes.erin.Lnd, nodes.erin.Tapd
107114
_, fabiaTap := nodes.fabia.Lnd, nodes.fabia.Tapd
108115
yara, yaraTap := nodes.yara.Lnd, nodes.yara.Tapd
116+
george, georgeTap := nodes.george.Lnd, nodes.george.Tapd
109117
universeTap := nodes.universeTap
110118

111119
// Let's open the normal sats channels between Charlie and the routing
@@ -131,6 +139,13 @@ func createTestMultiRFQAssetNetwork(t *harnessTest, net *NetworkHarness,
131139
},
132140
)
133141

142+
_ = openChannelAndAssert(
143+
t, net, charlie, george, lntest.OpenChannelParams{
144+
Amt: 10_000_000,
145+
SatPerVByte: 5,
146+
},
147+
)
148+
134149
ctxb := context.Background()
135150
assetID := mintedAsset.AssetGenesis.AssetId
136151
var groupKey []byte
@@ -225,6 +240,34 @@ func createTestMultiRFQAssetNetwork(t *harnessTest, net *NetworkHarness,
225240
)
226241
itest.AssertNonInteractiveRecvComplete(t.t, yaraTap, 1)
227242

243+
// We need to send some assets to George, so he can fund an asset
244+
// channel with Fabia.
245+
georgeAddr, err := georgeTap.NewAddr(ctxb, &taprpc.NewAddrRequest{
246+
Amt: assetSendAmount,
247+
AssetId: assetID,
248+
ProofCourierAddr: fmt.Sprintf(
249+
"%s://%s", proof.UniverseRpcCourierType,
250+
charlieTap.node.Cfg.LitAddr(),
251+
),
252+
})
253+
require.NoError(t.t, err)
254+
255+
t.Logf("Sending %v asset units to George...", assetSendAmount)
256+
257+
// Send the assets to George.
258+
itest.AssertAddrCreated(t.t, georgeTap, mintedAsset, georgeAddr)
259+
sendResp, err = charlieTap.SendAsset(ctxb, &taprpc.SendAssetRequest{
260+
TapAddrs: []string{georgeAddr.Encoded},
261+
})
262+
require.NoError(t.t, err)
263+
itest.ConfirmAndAssertOutboundTransfer(
264+
t.t, t.lndHarness.Miner.Client, charlieTap, sendResp, assetID,
265+
[]uint64{
266+
mintedAsset.Amount - 4*assetSendAmount, assetSendAmount,
267+
}, 3, 4,
268+
)
269+
itest.AssertNonInteractiveRecvComplete(t.t, georgeTap, 1)
270+
228271
// We fund the Dave->Fabia channel.
229272
fundRespDF, err := daveTap.FundChannel(
230273
ctxb, &tchrpc.FundChannelRequest{
@@ -264,6 +307,19 @@ func createTestMultiRFQAssetNetwork(t *harnessTest, net *NetworkHarness,
264307
require.NoError(t.t, err)
265308
t.Logf("Funded channel between Yara and Fabia: %v", fundRespYF)
266309

310+
// We fund the George->Fabia channel.
311+
fundRespGF, err := georgeTap.FundChannel(
312+
ctxb, &tchrpc.FundChannelRequest{
313+
AssetAmount: fundingAmount,
314+
AssetId: assetID,
315+
PeerPubkey: fabiaTap.node.PubKey[:],
316+
FeeRateSatPerVbyte: 5,
317+
PushSat: pushSat,
318+
},
319+
)
320+
require.NoError(t.t, err)
321+
t.Logf("Funded channel between George and Fabia: %v", fundRespGF)
322+
267323
// Make sure the pending channel shows up in the list and has the
268324
// custom records set as JSON.
269325
assertPendingChannels(
@@ -275,17 +331,21 @@ func createTestMultiRFQAssetNetwork(t *harnessTest, net *NetworkHarness,
275331
assertPendingChannels(
276332
t.t, yaraTap.node, mintedAsset, 1, fundingAmount, 0,
277333
)
334+
assertPendingChannels(
335+
t.t, georgeTap.node, mintedAsset, 1, fundingAmount, 0,
336+
)
278337

279338
// Now that we've looked at the pending channels, let's actually confirm
280339
// all three of them.
281-
mineBlocks(t, net, 6, 3)
340+
mineBlocks(t, net, 6, 4)
282341

283342
// We'll be tracking the expected asset balances throughout the test, so
284343
// we can assert it after each action.
285-
charlieAssetBalance := mintedAsset.Amount - 3*assetSendAmount
344+
charlieAssetBalance := mintedAsset.Amount - 4*assetSendAmount
286345
daveAssetBalance := assetSendAmount - fundingAmount
287346
erinAssetBalance := assetSendAmount - fundingAmount
288347
yaraAssetBalance := assetSendAmount - fundingAmount
348+
georgeAssetBalance := assetSendAmount - fundingAmount
289349

290350
itest.AssertBalances(
291351
t.t, charlieTap, charlieAssetBalance,
@@ -304,6 +364,10 @@ func createTestMultiRFQAssetNetwork(t *harnessTest, net *NetworkHarness,
304364
t.t, yaraTap, yaraAssetBalance, itest.WithAssetID(assetID),
305365
)
306366

367+
itest.AssertBalances(
368+
t.t, georgeTap, georgeAssetBalance, itest.WithAssetID(assetID),
369+
)
370+
307371
// Assert that the proofs for both channels has been uploaded to the
308372
// designated Universe server.
309373
assertUniverseProofExists(
@@ -318,6 +382,10 @@ func createTestMultiRFQAssetNetwork(t *harnessTest, net *NetworkHarness,
318382
t.t, universeTap, assetID, groupKey, fundingScriptTreeBytes,
319383
fmt.Sprintf("%v:%v", fundRespYF.Txid, fundRespYF.OutputIndex),
320384
)
385+
assertUniverseProofExists(
386+
t.t, universeTap, assetID, groupKey, fundingScriptTreeBytes,
387+
fmt.Sprintf("%v:%v", fundRespGF.Txid, fundRespGF.OutputIndex),
388+
)
321389

322390
return nil, nil, nil
323391
}
@@ -1355,7 +1423,7 @@ func sendAssetKeySendPayment(t *testing.T, src, dst *HarnessNode, amt uint64,
13551423
return
13561424
}
13571425

1358-
result, err := getAssetPaymentResult(stream, false)
1426+
result, _, err := getAssetPaymentResult(t, stream, false)
13591427
require.NoError(t, err)
13601428
if result.Status == lnrpc.Payment_FAILED {
13611429
t.Logf("Failure reason: %v", result.FailureReason)
@@ -1687,14 +1755,18 @@ func payInvoiceWithAssets(t *testing.T, payer, rfqPeer *HarnessNode,
16871755
sendReq.MaxShardSizeMsat = 80_000_000
16881756
}
16891757

1690-
var rfqBytes []byte
1758+
var rfqBytes, peerPubKey []byte
16911759
cfg.rfq.WhenSome(func(i rfqmsg.ID) {
16921760
rfqBytes = make([]byte, len(i[:]))
16931761
copy(rfqBytes, i[:])
16941762
})
16951763

1764+
if rfqPeer != nil {
1765+
peerPubKey = rfqPeer.PubKey[:]
1766+
}
1767+
16961768
request := &tchrpc.SendPaymentRequest{
1697-
PeerPubkey: rfqPeer.PubKey[:],
1769+
PeerPubkey: peerPubKey,
16981770
PaymentRequest: sendReq,
16991771
RfqId: rfqBytes,
17001772
AllowOverpay: cfg.allowOverpay,
@@ -1715,7 +1787,13 @@ func payInvoiceWithAssets(t *testing.T, payer, rfqPeer *HarnessNode,
17151787
// was established, no network or auth error), we expect the error to be
17161788
// returned on the first read on the stream.
17171789
if cfg.errSubStr != "" {
1718-
_, err := stream.Recv()
1790+
msg, err := stream.Recv()
1791+
1792+
// On errors we still get an empty set of RFQs as a response.
1793+
if msg.GetAcceptedSellOrders() != nil {
1794+
_, err = stream.Recv()
1795+
}
1796+
17191797
require.ErrorContains(t, err, cfg.errSubStr)
17201798

17211799
return 0, rfqmath.BigIntFixedPoint{}
@@ -1725,42 +1803,18 @@ func payInvoiceWithAssets(t *testing.T, payer, rfqPeer *HarnessNode,
17251803
numUnits uint64
17261804
rateVal rfqmath.FixedPoint[rfqmath.BigInt]
17271805
)
1728-
if cfg.rfq.IsNone() {
1729-
// We want to receive the accepted quote message first, so we
1730-
// know how many assets we're going to pay.
1731-
quoteMsg, err := stream.Recv()
1732-
require.NoError(t, err)
1733-
acceptedQuote := quoteMsg.GetAcceptedSellOrder()
1734-
require.NotNil(t, acceptedQuote)
1735-
1736-
peerPubKey := acceptedQuote.Peer
1737-
require.Equal(t, peerPubKey, rfqPeer.PubKeyStr)
1738-
1739-
rpcRate := acceptedQuote.BidAssetRate
1740-
rate, err := rpcutils.UnmarshalRfqFixedPoint(rpcRate)
1741-
require.NoError(t, err)
1742-
1743-
rateVal = *rate
17441806

1745-
t.Logf("Got quote for %v asset units per BTC", rate)
1746-
1747-
amountMsat := lnwire.MilliSatoshi(decodedInvoice.NumMsat)
1748-
milliSatsFP := rfqmath.MilliSatoshiToUnits(amountMsat, *rate)
1749-
numUnits = milliSatsFP.ScaleTo(0).ToUint64()
1750-
msatPerUnit := float64(decodedInvoice.NumMsat) /
1751-
float64(numUnits)
1752-
t.Logf("Got quote for %v asset units at %3f msat/unit from "+
1753-
"peer %s with SCID %d", numUnits, msatPerUnit,
1754-
peerPubKey, acceptedQuote.Scid)
1755-
}
1756-
1757-
result, err := getAssetPaymentResult(
1758-
stream, cfg.payStatus == lnrpc.Payment_IN_FLIGHT,
1807+
result, rateVal, err := getAssetPaymentResult(
1808+
t, stream, cfg.payStatus == lnrpc.Payment_IN_FLIGHT,
17591809
)
17601810
require.NoError(t, err)
17611811
require.Equal(t, cfg.payStatus, result.Status)
17621812
require.Equal(t, cfg.failureReason, result.FailureReason)
17631813

1814+
amountMsat := lnwire.MilliSatoshi(decodedInvoice.NumMsat)
1815+
milliSatsFP := rfqmath.MilliSatoshiToUnits(amountMsat, rateVal)
1816+
numUnits = milliSatsFP.ScaleTo(0).ToUint64()
1817+
17641818
return numUnits, rateVal
17651819
}
17661820

0 commit comments

Comments
 (0)