Skip to content

Commit 16b5b84

Browse files
committed
itest: add multi-rfq asset network creator
1 parent 482a6b6 commit 16b5b84

File tree

1 file changed

+255
-0
lines changed

1 file changed

+255
-0
lines changed

itest/assets_test.go

Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import (
3838
"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
3939
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
4040
"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
41+
"github.com/lightningnetwork/lnd/lntest"
4142
"github.com/lightningnetwork/lnd/lntest/rpc"
4243
"github.com/lightningnetwork/lnd/lntest/wait"
4344
"github.com/lightningnetwork/lnd/lntypes"
@@ -66,6 +67,260 @@ var (
6667
failureNone = lnrpc.PaymentFailureReason_FAILURE_REASON_NONE
6768
)
6869

70+
// itestNode is a wrapper around a lnd/tapd node.
71+
type itestNode struct {
72+
Lnd *HarnessNode
73+
Tapd *tapClient
74+
}
75+
76+
// multiRfqNodes contains all the itest nodes that are required to set up the
77+
// multi RFQ network topology.
78+
type multiRfqNodes struct {
79+
charlie, dave, erin, fabia, yara itestNode
80+
universeTap *tapClient
81+
}
82+
83+
// createTestMultiRFQAssetNetwork creates a lightning network topology which
84+
// consists of both bitcoin and asset channels. It focuses on the property of
85+
// having multiple channels available on both the sender and receiver side.
86+
//
87+
// The topology we are going for looks like the following:
88+
//
89+
// /---[sats]--> Erin --[assets]--\
90+
// / \
91+
// / \
92+
//
93+
// Charlie -----[sats]--> Dave --[assets]---->Fabia
94+
//
95+
// \ /
96+
// \ /
97+
// \---[sats]--> Yara --[assets]--/
98+
func createTestMultiRFQAssetNetwork(t *harnessTest, net *NetworkHarness,
99+
nodes multiRfqNodes, mintedAsset *taprpc.Asset, assetSendAmount,
100+
fundingAmount uint64, pushSat int64) (*lnrpc.ChannelPoint,
101+
*lnrpc.ChannelPoint, *lnrpc.ChannelPoint) {
102+
103+
charlie, charlieTap := nodes.charlie.Lnd, nodes.charlie.Tapd
104+
dave, daveTap := nodes.dave.Lnd, nodes.dave.Tapd
105+
erin, erinTap := nodes.erin.Lnd, nodes.erin.Tapd
106+
_, fabiaTap := nodes.fabia.Lnd, nodes.fabia.Tapd
107+
yara, yaraTap := nodes.yara.Lnd, nodes.yara.Tapd
108+
universeTap := nodes.universeTap
109+
110+
// Let's open the normal sats channels between Charlie and the routing
111+
// peers.
112+
_ = openChannelAndAssert(
113+
t, net, charlie, erin, lntest.OpenChannelParams{
114+
Amt: 10_000_000,
115+
SatPerVByte: 5,
116+
},
117+
)
118+
119+
_ = openChannelAndAssert(
120+
t, net, charlie, dave, lntest.OpenChannelParams{
121+
Amt: 10_000_000,
122+
SatPerVByte: 5,
123+
},
124+
)
125+
126+
_ = openChannelAndAssert(
127+
t, net, charlie, yara, lntest.OpenChannelParams{
128+
Amt: 10_000_000,
129+
SatPerVByte: 5,
130+
},
131+
)
132+
133+
ctxb := context.Background()
134+
assetID := mintedAsset.AssetGenesis.AssetId
135+
var groupKey []byte
136+
if mintedAsset.AssetGroup != nil {
137+
groupKey = mintedAsset.AssetGroup.TweakedGroupKey
138+
}
139+
140+
fundingScriptTree := tapscript.NewChannelFundingScriptTree()
141+
fundingScriptKey := fundingScriptTree.TaprootKey
142+
fundingScriptTreeBytes := fundingScriptKey.SerializeCompressed()
143+
144+
// We need to send some assets to Dave, so he can fund an asset channel
145+
// with Fabia.
146+
daveAddr, err := daveTap.NewAddr(ctxb, &taprpc.NewAddrRequest{
147+
Amt: assetSendAmount,
148+
AssetId: assetID,
149+
ProofCourierAddr: fmt.Sprintf(
150+
"%s://%s", proof.UniverseRpcCourierType,
151+
charlieTap.node.Cfg.LitAddr(),
152+
),
153+
})
154+
require.NoError(t.t, err)
155+
156+
t.Logf("Sending %v asset units to Dave...", assetSendAmount)
157+
158+
// Send the assets to Dave.
159+
itest.AssertAddrCreated(t.t, daveTap, mintedAsset, daveAddr)
160+
sendResp, err := charlieTap.SendAsset(ctxb, &taprpc.SendAssetRequest{
161+
TapAddrs: []string{daveAddr.Encoded},
162+
})
163+
require.NoError(t.t, err)
164+
itest.ConfirmAndAssertOutboundTransfer(
165+
t.t, t.lndHarness.Miner.Client, charlieTap, sendResp, assetID,
166+
[]uint64{mintedAsset.Amount - assetSendAmount, assetSendAmount},
167+
0, 1,
168+
)
169+
itest.AssertNonInteractiveRecvComplete(t.t, daveTap, 1)
170+
171+
// We need to send some assets to Erin, so he can fund an asset channel
172+
// with Fabia.
173+
erinAddr, err := erinTap.NewAddr(ctxb, &taprpc.NewAddrRequest{
174+
Amt: assetSendAmount,
175+
AssetId: assetID,
176+
ProofCourierAddr: fmt.Sprintf(
177+
"%s://%s", proof.UniverseRpcCourierType,
178+
charlieTap.node.Cfg.LitAddr(),
179+
),
180+
})
181+
require.NoError(t.t, err)
182+
183+
t.Logf("Sending %v asset units to Erin...", assetSendAmount)
184+
185+
// Send the assets to Erin.
186+
itest.AssertAddrCreated(t.t, erinTap, mintedAsset, erinAddr)
187+
sendResp, err = charlieTap.SendAsset(ctxb, &taprpc.SendAssetRequest{
188+
TapAddrs: []string{erinAddr.Encoded},
189+
})
190+
require.NoError(t.t, err)
191+
itest.ConfirmAndAssertOutboundTransfer(
192+
t.t, t.lndHarness.Miner.Client, charlieTap, sendResp, assetID,
193+
[]uint64{
194+
mintedAsset.Amount - 2*assetSendAmount, assetSendAmount,
195+
}, 1, 2,
196+
)
197+
itest.AssertNonInteractiveRecvComplete(t.t, erinTap, 1)
198+
199+
// We need to send some assets to Yara, so he can fund an asset channel
200+
// with Fabia.
201+
yaraAddr, err := yaraTap.NewAddr(ctxb, &taprpc.NewAddrRequest{
202+
Amt: assetSendAmount,
203+
AssetId: assetID,
204+
ProofCourierAddr: fmt.Sprintf(
205+
"%s://%s", proof.UniverseRpcCourierType,
206+
charlieTap.node.Cfg.LitAddr(),
207+
),
208+
})
209+
require.NoError(t.t, err)
210+
211+
t.Logf("Sending %v asset units to Yara...", assetSendAmount)
212+
213+
// Send the assets to Yara.
214+
itest.AssertAddrCreated(t.t, yaraTap, mintedAsset, yaraAddr)
215+
sendResp, err = charlieTap.SendAsset(ctxb, &taprpc.SendAssetRequest{
216+
TapAddrs: []string{yaraAddr.Encoded},
217+
})
218+
require.NoError(t.t, err)
219+
itest.ConfirmAndAssertOutboundTransfer(
220+
t.t, t.lndHarness.Miner.Client, charlieTap, sendResp, assetID,
221+
[]uint64{
222+
mintedAsset.Amount - 3*assetSendAmount, assetSendAmount,
223+
}, 2, 3,
224+
)
225+
itest.AssertNonInteractiveRecvComplete(t.t, yaraTap, 1)
226+
227+
// We fund the Dave->Fabia channel.
228+
fundRespDF, err := daveTap.FundChannel(
229+
ctxb, &tchrpc.FundChannelRequest{
230+
AssetAmount: fundingAmount,
231+
AssetId: assetID,
232+
PeerPubkey: fabiaTap.node.PubKey[:],
233+
FeeRateSatPerVbyte: 5,
234+
PushSat: pushSat,
235+
},
236+
)
237+
require.NoError(t.t, err)
238+
t.Logf("Funded channel between Dave and Fabia: %v", fundRespDF)
239+
240+
// We fund the Erin->Fabia channel.
241+
fundRespEF, err := erinTap.FundChannel(
242+
ctxb, &tchrpc.FundChannelRequest{
243+
AssetAmount: fundingAmount,
244+
AssetId: assetID,
245+
PeerPubkey: fabiaTap.node.PubKey[:],
246+
FeeRateSatPerVbyte: 5,
247+
PushSat: pushSat,
248+
},
249+
)
250+
require.NoError(t.t, err)
251+
t.Logf("Funded channel between Erin and Fabia: %v", fundRespEF)
252+
253+
// We fund the Yara->Fabia channel.
254+
fundRespYF, err := yaraTap.FundChannel(
255+
ctxb, &tchrpc.FundChannelRequest{
256+
AssetAmount: fundingAmount,
257+
AssetId: assetID,
258+
PeerPubkey: fabiaTap.node.PubKey[:],
259+
FeeRateSatPerVbyte: 5,
260+
PushSat: pushSat,
261+
},
262+
)
263+
require.NoError(t.t, err)
264+
t.Logf("Funded channel between Yara and Fabia: %v", fundRespYF)
265+
266+
// Make sure the pending channel shows up in the list and has the
267+
// custom records set as JSON.
268+
assertPendingChannels(
269+
t.t, daveTap.node, mintedAsset, 1, fundingAmount, 0,
270+
)
271+
assertPendingChannels(
272+
t.t, erinTap.node, mintedAsset, 1, fundingAmount, 0,
273+
)
274+
assertPendingChannels(
275+
t.t, yaraTap.node, mintedAsset, 1, fundingAmount, 0,
276+
)
277+
278+
// Now that we've looked at the pending channels, let's actually confirm
279+
// all three of them.
280+
mineBlocks(t, net, 6, 3)
281+
282+
// We'll be tracking the expected asset balances throughout the test, so
283+
// we can assert it after each action.
284+
charlieAssetBalance := mintedAsset.Amount - 3*assetSendAmount
285+
daveAssetBalance := assetSendAmount - fundingAmount
286+
erinAssetBalance := assetSendAmount - fundingAmount
287+
yaraAssetBalance := assetSendAmount - fundingAmount
288+
289+
itest.AssertBalances(
290+
t.t, charlieTap, charlieAssetBalance,
291+
itest.WithAssetID(assetID), itest.WithNumUtxos(1),
292+
)
293+
294+
itest.AssertBalances(
295+
t.t, daveTap, daveAssetBalance, itest.WithAssetID(assetID),
296+
)
297+
298+
itest.AssertBalances(
299+
t.t, erinTap, erinAssetBalance, itest.WithAssetID(assetID),
300+
)
301+
302+
itest.AssertBalances(
303+
t.t, yaraTap, yaraAssetBalance, itest.WithAssetID(assetID),
304+
)
305+
306+
// Assert that the proofs for both channels has been uploaded to the
307+
// designated Universe server.
308+
assertUniverseProofExists(
309+
t.t, universeTap, assetID, groupKey, fundingScriptTreeBytes,
310+
fmt.Sprintf("%v:%v", fundRespDF.Txid, fundRespDF.OutputIndex),
311+
)
312+
assertUniverseProofExists(
313+
t.t, universeTap, assetID, groupKey, fundingScriptTreeBytes,
314+
fmt.Sprintf("%v:%v", fundRespEF.Txid, fundRespEF.OutputIndex),
315+
)
316+
assertUniverseProofExists(
317+
t.t, universeTap, assetID, groupKey, fundingScriptTreeBytes,
318+
fmt.Sprintf("%v:%v", fundRespYF.Txid, fundRespYF.OutputIndex),
319+
)
320+
321+
return nil, nil, nil
322+
}
323+
69324
// createTestAssetNetwork sends asset funds from Charlie to Dave and Erin, so
70325
// they can fund asset channels with Yara and Fabia, respectively. So the asset
71326
// channels created are Charlie->Dave, Dave->Yara, Erin->Fabia. The channels

0 commit comments

Comments
 (0)