@@ -258,14 +258,15 @@ func createTestAssetNetwork(t *harnessTest, net *NetworkHarness, charlieTap,
258258	// Make sure the channel shows the correct asset information. 
259259	assertAssetChan (
260260		t .t , charlieTap .node , daveTap .node , charlieFundingAmount ,
261- 		mintedAsset ,
261+ 		[] * taprpc. Asset { mintedAsset } ,
262262	)
263263	assertAssetChan (
264- 		t .t , daveTap .node , yaraTap .node , daveFundingAmount , mintedAsset ,
264+ 		t .t , daveTap .node , yaraTap .node , daveFundingAmount ,
265+ 		[]* taprpc.Asset {mintedAsset },
265266	)
266267	assertAssetChan (
267268		t .t , erinTap .node , fabiaTap .node , erinFundingAmount ,
268- 		mintedAsset ,
269+ 		[] * taprpc. Asset { mintedAsset } ,
269270	)
270271
271272	chanPointCD  :=  & lnrpc.ChannelPoint {
@@ -473,7 +474,7 @@ func assertPendingChannels(t *testing.T, node *HarnessNode,
473474		pendingChan .Channel .CustomChannelData , & pendingJSON ,
474475	)
475476	require .NoError (t , err )
476- 	require .Len (t , pendingJSON .FundingAssets , 1 )
477+ 	require .GreaterOrEqual (t , len ( pendingJSON .FundingAssets ) , 1 )
477478
478479	require .NotZero (t , pendingJSON .Capacity )
479480
@@ -494,9 +495,7 @@ func assertPendingChannels(t *testing.T, node *HarnessNode,
494495	// Check the balance of the pending channel. 
495496	assetID  :=  mintedAsset .AssetGenesis .AssetId 
496497	pendingLocalBalance , pendingRemoteBalance , _ , _  := 
497- 		getAssetChannelBalance (
498- 			t , node , assetID , true ,
499- 		)
498+ 		getAssetChannelBalance (t , node , [][]byte {assetID }, true )
500499	require .EqualValues (t , localSum , pendingLocalBalance )
501500	require .EqualValues (t , remoteSum , pendingRemoteBalance )
502501}
@@ -517,18 +516,20 @@ func haveFundingAsset(assetChannel *rfqmsg.JsonAssetChannel,
517516}
518517
519518func  assertAssetChan (t  * testing.T , src , dst  * HarnessNode , fundingAmount  uint64 ,
520- 	channelAsset   * taprpc.Asset ) {
519+ 	channelAssets  [] * taprpc.Asset ) {
521520
522521	err  :=  wait .NoError (func () error  {
523522		a , err  :=  getChannelCustomData (src , dst )
524523		if  err  !=  nil  {
525524			return  err 
526525		}
527526
528- 		assetID  :=  channelAsset .AssetGenesis .AssetId 
529- 		if  ! haveFundingAsset (a , assetID ) {
530- 			return  fmt .Errorf ("expected asset ID %x, to " + 
531- 				"be in channel" , assetID )
527+ 		for  _ , channelAsset  :=  range  channelAssets  {
528+ 			assetID  :=  channelAsset .AssetGenesis .AssetId 
529+ 			if  ! haveFundingAsset (a , assetID ) {
530+ 				return  fmt .Errorf ("expected asset ID %x, to " + 
531+ 					"be in channel" , assetID )
532+ 			}
532533		}
533534
534535		if  a .Capacity  !=  fundingAmount  {
@@ -541,9 +542,9 @@ func assertAssetChan(t *testing.T, src, dst *HarnessNode, fundingAmount uint64,
541542		// We only need to check the first funding asset, since we 
542543		// enforce them to be the same. 
543544		var  expectedDecimalDisplay  uint8 
544- 		if  channelAsset .DecimalDisplay  !=  nil  {
545+ 		if  channelAssets [ 0 ] .DecimalDisplay  !=  nil  {
545546			expectedDecimalDisplay  =  uint8 (
546- 				channelAsset .DecimalDisplay .DecimalDisplay ,
547+ 				channelAssets [ 0 ] .DecimalDisplay .DecimalDisplay ,
547548			)
548549		}
549550
@@ -639,7 +640,7 @@ func getChannelCustomData(src, dst *HarnessNode) (*rfqmsg.JsonAssetChannel,
639640	return  & assetData , nil 
640641}
641642
642- func  getAssetChannelBalance (t  * testing.T , node  * HarnessNode , assetID   []byte ,
643+ func  getAssetChannelBalance (t  * testing.T , node  * HarnessNode , assetIDs  [] []byte ,
643644	pending  bool ) (uint64 , uint64 , uint64 , uint64 ) {
644645
645646	ctxb  :=  context .Background ()
@@ -651,18 +652,34 @@ func getAssetChannelBalance(t *testing.T, node *HarnessNode, assetID []byte,
651652	)
652653	require .NoError (t , err )
653654
655+ 	// In case there are no channels, the custom channel data will just be 
656+ 	// empty. Which means the total asset balance is zero. 
657+ 	if  len (balance .CustomChannelData ) ==  0  {
658+ 		return  0 , 0 , 0 , 0 
659+ 	}
660+ 
654661	var  assetBalance  rfqmsg.JsonAssetChannelBalances 
655662	err  =  json .Unmarshal (balance .CustomChannelData , & assetBalance )
656- 	require .NoError (t , err )
663+ 	require .NoErrorf (t , err ,  "json: '%x'" ,  balance . CustomChannelData )
657664
658665	balances  :=  assetBalance .OpenChannels 
659666	if  pending  {
660667		balances  =  assetBalance .PendingChannels 
661668	}
662669
670+ 	idMatch  :=  func (assetIDString  string ) bool  {
671+ 		for  _ , groupedID  :=  range  assetIDs  {
672+ 			if  assetIDString  ==  hex .EncodeToString (groupedID ) {
673+ 				return  true 
674+ 			}
675+ 		}
676+ 
677+ 		return  false 
678+ 	}
679+ 
663680	var  localSum , remoteSum  uint64 
664681	for  assetIDString  :=  range  balances  {
665- 		if  assetIDString   !=   hex . EncodeToString ( assetID ) {
682+ 		if  ! idMatch ( assetIDString ) {
666683			continue 
667684		}
668685
@@ -1368,12 +1385,12 @@ func waitForSendEvent(t *testing.T,
13681385// transaction. 
13691386type  coOpCloseBalanceCheck  func (t  * testing.T , local , remote  * HarnessNode ,
13701387	closeTx  * wire.MsgTx , closeUpdate  * lnrpc.ChannelCloseUpdate ,
1371- 	assetID , groupKey  []byte , universeTap  * tapClient )
1388+ 	assetIDs  [][] byte , groupKey  []byte , universeTap  * tapClient )
13721389
13731390// noOpCoOpCloseBalanceCheck is a no-op implementation of the co-op close 
13741391// balance check that can be used in tests. 
13751392func  noOpCoOpCloseBalanceCheck (_  * testing.T , _ , _  * HarnessNode , _  * wire.MsgTx ,
1376- 	_  * lnrpc.ChannelCloseUpdate , _ , _  []byte , _  * tapClient ) {
1393+ 	_  * lnrpc.ChannelCloseUpdate , _  [][] byte , _  []byte , _  * tapClient ) {
13771394
13781395	// This is a no-op function. 
13791396}
@@ -1382,7 +1399,7 @@ func noOpCoOpCloseBalanceCheck(_ *testing.T, _, _ *HarnessNode, _ *wire.MsgTx,
13821399// node and asserts the final balances of the closing transaction. 
13831400func  closeAssetChannelAndAssert (t  * harnessTest , net  * NetworkHarness ,
13841401	local , remote  * HarnessNode , chanPoint  * lnrpc.ChannelPoint ,
1385- 	assetID , groupKey  []byte , universeTap  * tapClient ,
1402+ 	assetIDs  [][] byte , groupKey  []byte , universeTap  * tapClient ,
13861403	balanceCheck  coOpCloseBalanceCheck ) {
13871404
13881405	t .t .Helper ()
@@ -1422,7 +1439,7 @@ func closeAssetChannelAndAssert(t *harnessTest, net *NetworkHarness,
14221439
14231440	// Check the final balance of the closing transaction. 
14241441	balanceCheck (
1425- 		t .t , local , remote , closeTx , closeUpdate , assetID , groupKey ,
1442+ 		t .t , local , remote , closeTx , closeUpdate , assetIDs , groupKey ,
14261443		universeTap ,
14271444	)
14281445
@@ -1439,10 +1456,10 @@ func assertDefaultCoOpCloseBalance(remoteBtcBalance,
14391456
14401457	return  func (t  * testing.T , local , remote  * HarnessNode ,
14411458		closeTx  * wire.MsgTx , closeUpdate  * lnrpc.ChannelCloseUpdate ,
1442- 		assetID , groupKey  []byte , universeTap  * tapClient ) {
1459+ 		assetIDs  [][] byte , groupKey  []byte , universeTap  * tapClient ) {
14431460
14441461		defaultCoOpCloseBalanceCheck (
1445- 			t , local , remote , closeTx , closeUpdate , assetID ,
1462+ 			t , local , remote , closeTx , closeUpdate , assetIDs ,
14461463			groupKey , universeTap , remoteBtcBalance ,
14471464			remoteAssetBalance ,
14481465		)
@@ -1455,8 +1472,8 @@ func assertDefaultCoOpCloseBalance(remoteBtcBalance,
14551472// with the boolean variables. 
14561473func  defaultCoOpCloseBalanceCheck (t  * testing.T , local , remote  * HarnessNode ,
14571474	closeTx  * wire.MsgTx , closeUpdate  * lnrpc.ChannelCloseUpdate ,
1458- 	assetID , groupKey  []byte , universeTap  * tapClient ,  remoteBtcBalance ,
1459- 	remoteAssetBalance  bool ) {
1475+ 	assetIDs  [][] byte , groupKey  []byte , universeTap  * tapClient ,
1476+ 	remoteBtcBalance ,  remoteAssetBalance  bool ) {
14601477
14611478	// With the channel closed, we'll now assert that the co-op close 
14621479	// transaction was inserted into the local universe. 
@@ -1563,11 +1580,15 @@ func defaultCoOpCloseBalanceCheck(t *testing.T, local, remote *HarnessNode,
15631580	)
15641581	require .NoError (t , err )
15651582
1583+ 	assetIDStrings  :=  fn .Map (hex .EncodeToString , assetIDs )
15661584	for  assetIDStr , scriptKeyStr  :=  range  localAssetCloseOut .ScriptKeys  {
15671585		scriptKeyBytes , err  :=  hex .DecodeString (scriptKeyStr )
15681586		require .NoError (t , err )
15691587
1570- 		require .Equal (t , hex .EncodeToString (assetID ), assetIDStr )
1588+ 		require .Contains (t , assetIDStrings , assetIDStr )
1589+ 
1590+ 		assetID , err  :=  hex .DecodeString (assetIDStr )
1591+ 		require .NoError (t , err )
15711592
15721593		a  :=  assertUniverseProofExists (
15731594			t , universeTap , assetID , groupKey , scriptKeyBytes ,
@@ -1605,7 +1626,10 @@ func defaultCoOpCloseBalanceCheck(t *testing.T, local, remote *HarnessNode,
16051626		scriptKeyBytes , err  :=  hex .DecodeString (scriptKeyStr )
16061627		require .NoError (t , err )
16071628
1608- 		require .Equal (t , hex .EncodeToString (assetID ), assetIDStr )
1629+ 		require .Contains (t , assetIDStrings , assetIDStr )
1630+ 
1631+ 		assetID , err  :=  hex .DecodeString (assetIDStr )
1632+ 		require .NoError (t , err )
16091633
16101634		a  :=  assertUniverseProofExists (
16111635			t , universeTap , assetID , groupKey , scriptKeyBytes ,
@@ -1627,8 +1651,8 @@ func defaultCoOpCloseBalanceCheck(t *testing.T, local, remote *HarnessNode,
16271651// function that can be used when the initiator has a zero asset balance. 
16281652func  initiatorZeroAssetBalanceCoOpBalanceCheck (t  * testing.T , _ ,
16291653	remote  * HarnessNode , closeTx  * wire.MsgTx ,
1630- 	closeUpdate  * lnrpc.ChannelCloseUpdate , assetID ,  groupKey   []byte ,
1631- 	universeTap  * tapClient ) {
1654+ 	closeUpdate  * lnrpc.ChannelCloseUpdate , assetIDs  [] []byte ,
1655+ 	groupKey  [] byte ,  universeTap  * tapClient ) {
16321656
16331657	// With the channel closed, we'll now assert that the co-op close 
16341658	// transaction was inserted into the local universe. 
@@ -1674,11 +1698,15 @@ func initiatorZeroAssetBalanceCoOpBalanceCheck(t *testing.T, _,
16741698	)
16751699	require .NoError (t , err )
16761700
1701+ 	assetIDStrings  :=  fn .Map (hex .EncodeToString , assetIDs )
16771702	for  assetIDStr , scriptKeyStr  :=  range  remoteAssetCloseOut .ScriptKeys  {
16781703		scriptKeyBytes , err  :=  hex .DecodeString (scriptKeyStr )
16791704		require .NoError (t , err )
16801705
1681- 		require .Equal (t , hex .EncodeToString (assetID ), assetIDStr )
1706+ 		require .Contains (t , assetIDStrings , assetIDStr )
1707+ 
1708+ 		assetID , err  :=  hex .DecodeString (assetIDStr )
1709+ 		require .NoError (t , err )
16821710
16831711		a  :=  assertUniverseProofExists (
16841712			t , universeTap , assetID , groupKey , scriptKeyBytes ,
@@ -1821,12 +1849,15 @@ func assertAssetBalance(t *testing.T, client *tapClient, assetID []byte,
18211849		},
18221850	}
18231851
1852+ 	var  lastBalances  * taprpc.ListBalancesResponse 
18241853	err  :=  wait .NoError (func () error  {
18251854		assetIDBalances , err  :=  client .ListBalances (ctxt , req )
18261855		if  err  !=  nil  {
18271856			return  err 
18281857		}
18291858
1859+ 		lastBalances  =  assetIDBalances 
1860+ 
18301861		assetIDFound  :=  false 
18311862		for  _ , balance  :=  range  assetIDBalances .AssetBalances  {
18321863			if  ! bytes .Equal (balance .AssetGenesis .AssetId , assetID ) {
@@ -1847,11 +1878,16 @@ func assertAssetBalance(t *testing.T, client *tapClient, assetID []byte,
18471878		return  nil 
18481879	}, shortTimeout )
18491880	if  err  !=  nil  {
1850- 		r , err2  :=  client .ListAssets (ctxb , & taprpc.ListAssetRequest {})
1881+ 		listAssetsResp , err2  :=  client .ListAssets (
1882+ 			ctxb , & taprpc.ListAssetRequest {},
1883+ 		)
18511884		require .NoError (t , err2 )
18521885
1853- 		t .Logf ("Failed to assert expected balance of %d, current " + 
1854- 			"assets: %v" , expectedBalance , toProtoJSON (t , r ))
1886+ 		t .Logf ("Failed to assert expected balance of %d for asset ID " + 
1887+ 			"%x: %v" , expectedBalance , assetID , err )
1888+ 
1889+ 		t .Logf ("Last balances: %v" , toProtoJSON (t , lastBalances ))
1890+ 		t .Logf ("Current assets: %v" , toProtoJSON (t , listAssetsResp ))
18551891
18561892		utxos , err3  :=  client .ListUtxos (
18571893			ctxb , & taprpc.ListUtxosRequest {},
@@ -2031,8 +2067,9 @@ func logBalance(t *testing.T, nodes []*HarnessNode, assetID []byte,
20312067	time .Sleep (time .Millisecond  *  250 )
20322068
20332069	for  _ , node  :=  range  nodes  {
2034- 		local , remote , localSat , remoteSat  := 
2035- 			getAssetChannelBalance (t , node , assetID , false )
2070+ 		local , remote , localSat , remoteSat  :=  getAssetChannelBalance (
2071+ 			t , node , [][]byte {assetID }, false ,
2072+ 		)
20362073
20372074		t .Logf ("%-7s balance: local=%-9d remote=%-9d, localSat=%-9d, " + 
20382075			"remoteSat=%-9d (%v)" , node .Cfg .Name , local , remote ,
@@ -2363,3 +2400,47 @@ func assertClosedChannelAssetData(t *testing.T, node *HarnessNode,
23632400
23642401	require .GreaterOrEqual (t , len (closeData .FundingAssets ), 1 )
23652402}
2403+ 
2404+ func  findForceCloseTransfer (t  * testing.T , node1 , node2  * tapClient ,
2405+ 	closeTxid  * chainhash.Hash ) * taprpc.ListTransfersResponse  {
2406+ 
2407+ 	var  (
2408+ 		ctxb    =  context .Background ()
2409+ 		result  * taprpc.ListTransfersResponse 
2410+ 		err     error 
2411+ 	)
2412+ 	fErr  :=  wait .NoError (func () error  {
2413+ 		result , err  =  node1 .ListTransfers (
2414+ 			ctxb , & taprpc.ListTransfersRequest {
2415+ 				AnchorTxid : closeTxid .String (),
2416+ 			},
2417+ 		)
2418+ 		if  err  !=  nil  {
2419+ 			return  fmt .Errorf ("unable to list node1 transfers: %w" ,
2420+ 				err )
2421+ 		}
2422+ 		if  len (result .Transfers ) !=  1  {
2423+ 			return  fmt .Errorf ("node1 is missing force close "  + 
2424+ 				"transfer" )
2425+ 		}
2426+ 
2427+ 		forceCloseTransfer2 , err  :=  node2 .ListTransfers (
2428+ 			ctxb , & taprpc.ListTransfersRequest {
2429+ 				AnchorTxid : closeTxid .String (),
2430+ 			},
2431+ 		)
2432+ 		if  err  !=  nil  {
2433+ 			return  fmt .Errorf ("unable to list node2 transfers: %w" ,
2434+ 				err )
2435+ 		}
2436+ 		if  len (forceCloseTransfer2 .Transfers ) !=  1  {
2437+ 			return  fmt .Errorf ("node2 is missing force close "  + 
2438+ 				"transfer" )
2439+ 		}
2440+ 
2441+ 		return  nil 
2442+ 	}, defaultTimeout )
2443+ 	require .NoError (t , fErr )
2444+ 
2445+ 	return  result 
2446+ }
0 commit comments