Skip to content

Commit dd85d50

Browse files
authored
Merge pull request #1741 from lightninglabs/passive-asset-split-output-fix
bugfix: fix two long-existing edge case bugs
2 parents d04ab96 + 5488ad7 commit dd85d50

File tree

12 files changed

+701
-65
lines changed

12 files changed

+701
-65
lines changed

docs/release-notes/release-notes-0.7.0.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,16 @@
2626
- [An integration test flake was
2727
fixed](https://github.com/lightninglabs/taproot-assets/pull/1651).
2828

29+
- Fixed two send related bugs that would lead to either a `invalid transfer
30+
asset witness` or `unable to fund address send: error funding packet: unable
31+
to list eligible coins: unable to query commitments: mismatch of managed utxo
32+
and constructed tap commitment root` error when sending assets.
33+
The [PR that fixed the two
34+
bugs](https://github.com/lightninglabs/taproot-assets/pull/1741) also
35+
optimized sending to V2 TAP addresses by removing the need for creating
36+
tombstone outputs on a full-value send (by using interactive transfers for V2
37+
addresses).
38+
2939
# New Features
3040

3141
## Functional Enhancements

itest/addrs_v2_test.go

Lines changed: 261 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -271,8 +271,7 @@ func testAddressV2WithGroupKey(t *harnessTest) {
271271
AssertAssetOutboundTransferWithOutputs(
272272
t.t, t.lndHarness.Miner().Client, t.tapd,
273273
sendResp.Transfer, [][]byte{firstAssetID, secondAssetID},
274-
[]uint64{0, firstAsset.Amount, 0, secondAsset.Amount}, 0,
275-
1, 4, true,
274+
[]uint64{firstAsset.Amount, secondAsset.Amount}, 0, 1, 2, true,
276275
)
277276
AssertReceiveEventsCustom(t.t, addrEvents, []taprpc.AddrEventStatus{
278277
statusConfirmed,
@@ -284,13 +283,6 @@ func testAddressV2WithGroupKey(t *harnessTest) {
284283
WithNumUtxos(2),
285284
)
286285

287-
// The sending node should only have two tombstone outputs, but the
288-
// total value should be zero.
289-
AssertBalanceByGroup(
290-
t.t, t.tapd, hex.EncodeToString(groupKey), 0, WithNumUtxos(2),
291-
WithAllScriptKeyTypes(),
292-
)
293-
294286
// We now make sure we can spend those assets again by sending
295287
// them back to ourselves, using an address with an amount.
296288
groupAddrBob2, _ := NewAddrWithEventStream(
@@ -354,8 +346,8 @@ func testAddressV2WithGroupKey(t *harnessTest) {
354346
AssertAssetOutboundTransferWithOutputs(
355347
t.t, t.lndHarness.Miner().Client, bobTapd,
356348
sendResp3.Transfer, [][]byte{firstAssetID, secondAssetID},
357-
[]uint64{0, totalAmount/2 - 50, 50, 0, totalAmount / 2}, 1,
358-
2, 5, true,
349+
[]uint64{totalAmount/2 - 50, 50, totalAmount / 2}, 1, 2, 3,
350+
true,
359351
)
360352
AssertBalanceByGroup(
361353
t.t, t.tapd, hex.EncodeToString(groupKey), totalAmount,
@@ -396,6 +388,264 @@ func testAddressV2WithGroupKey(t *harnessTest) {
396388
)
397389
}
398390

391+
// testAddressV2WithGroupKeyMultipleRoundTrips tests what we can send assets
392+
// back and forth multiple times using V2 addresses.
393+
func testAddressV2WithGroupKeyMultipleRoundTrips(t *harnessTest) {
394+
// We begin by minting a new asset group with a group key.
395+
firstTrancheReq := CopyRequest(issuableAssets[0])
396+
397+
firstTrancheReq.Asset.Amount = 212e5
398+
399+
firstTranche := MintAssetsConfirmBatch(
400+
t.t, t.lndHarness.Miner().Client, t.tapd,
401+
[]*mintrpc.MintAssetRequest{firstTrancheReq},
402+
)
403+
firstAsset := firstTranche[0]
404+
firstAssetID := firstAsset.AssetGenesis.AssetId
405+
groupKey := firstAsset.AssetGroup.TweakedGroupKey
406+
407+
// And then we mint a second tranche of the same asset group.
408+
secondTrancheReq := CopyRequest(firstTrancheReq)
409+
secondTrancheReq.Asset.Name = "itestbuxx-money-printer-brrr-tranche-2"
410+
secondTrancheReq.Asset.GroupedAsset = true
411+
secondTrancheReq.Asset.NewGroupedAsset = false
412+
secondTrancheReq.Asset.GroupKey = groupKey
413+
414+
secondTrancheReq.Asset.Amount = 202e5
415+
416+
secondTranche := MintAssetsConfirmBatch(
417+
t.t, t.lndHarness.Miner().Client, t.tapd,
418+
[]*mintrpc.MintAssetRequest{secondTrancheReq},
419+
)
420+
secondAsset := secondTranche[0]
421+
secondAssetID := secondAsset.AssetGenesis.AssetId
422+
423+
// And then we mint a third tranche of the same asset group.
424+
thirdTrancheReq := CopyRequest(firstTrancheReq)
425+
thirdTrancheReq.Asset.Name = "itestbuxx-money-printer-brrr-tranche-3"
426+
thirdTrancheReq.Asset.GroupedAsset = true
427+
thirdTrancheReq.Asset.NewGroupedAsset = false
428+
thirdTrancheReq.Asset.GroupKey = groupKey
429+
430+
thirdTrancheReq.Asset.Amount = 182e5
431+
432+
thirdTranche := MintAssetsConfirmBatch(
433+
t.t, t.lndHarness.Miner().Client, t.tapd,
434+
[]*mintrpc.MintAssetRequest{thirdTrancheReq},
435+
)
436+
thirdAsset := thirdTranche[0]
437+
thirdAssetID := thirdAsset.AssetGenesis.AssetId
438+
439+
ctxb := context.Background()
440+
ctxt, cancel := context.WithTimeout(ctxb, defaultWaitTimeout)
441+
defer cancel()
442+
443+
totalAmount := firstAsset.Amount + secondAsset.Amount +
444+
thirdAsset.Amount
445+
t.Logf("Minted %d units for group %x", totalAmount, groupKey)
446+
447+
// Now we can create an address with the group key.
448+
// We'll make a second node now that'll be the receiver of all the
449+
// assets made above.
450+
bobLnd := t.lndHarness.NewNodeWithCoins("Bob", nil)
451+
bobTapd := setupTapdHarness(t.t, t, bobLnd, t.universeServer)
452+
defer func() {
453+
require.NoError(t.t, bobTapd.stop(!*noDelete))
454+
}()
455+
456+
groupAddrBob, _ := NewAddrWithEventStream(
457+
t.t, bobTapd, &taprpc.NewAddrRequest{
458+
AddressVersion: taprpc.AddrVersion_ADDR_VERSION_V2,
459+
GroupKey: groupKey,
460+
},
461+
)
462+
463+
t.Logf("Got group addr: %v", toJSON(t.t, groupAddrBob))
464+
465+
currentTransferIdx := -1
466+
numTransfers := 0
467+
468+
bobCurrentTransferIdx := -1
469+
bobNumTransfers := 0
470+
471+
// We send the first tranche from alice to bob.
472+
currentTransferIdx += 1
473+
numTransfers += 1
474+
475+
sendResp, err := t.tapd.SendAsset(ctxt, &taprpc.SendAssetRequest{
476+
AddressesWithAmounts: []*taprpc.AddressWithAmount{
477+
{
478+
TapAddr: groupAddrBob.Encoded,
479+
Amount: firstAsset.Amount,
480+
},
481+
},
482+
})
483+
require.NoError(t.t, err)
484+
t.Logf("Sent asset to group addr: %v", toJSON(t.t, sendResp))
485+
AssertAssetOutboundTransferWithOutputs(
486+
t.t, t.lndHarness.Miner().Client, t.tapd,
487+
sendResp.Transfer, [][]byte{firstAssetID},
488+
[]uint64{firstAsset.Amount}, currentTransferIdx,
489+
numTransfers, 1, true,
490+
)
491+
492+
AssertAddrEventByStatus(t.t, bobTapd, statusCompleted, numTransfers)
493+
494+
// Then we send the second tranche from alice to bob.
495+
currentTransferIdx += 1
496+
numTransfers += 1
497+
498+
sendResp, err = t.tapd.SendAsset(ctxt, &taprpc.SendAssetRequest{
499+
AddressesWithAmounts: []*taprpc.AddressWithAmount{
500+
{
501+
TapAddr: groupAddrBob.Encoded,
502+
Amount: secondAsset.Amount,
503+
},
504+
},
505+
})
506+
require.NoError(t.t, err)
507+
t.Logf("Sent asset to group addr: %v", toJSON(t.t, sendResp))
508+
AssertAssetOutboundTransferWithOutputs(
509+
t.t, t.lndHarness.Miner().Client, t.tapd,
510+
sendResp.Transfer, [][]byte{secondAssetID},
511+
[]uint64{secondAsset.Amount}, currentTransferIdx,
512+
numTransfers, 1, true,
513+
)
514+
515+
AssertAddrEventByStatus(t.t, bobTapd, statusCompleted, numTransfers)
516+
517+
// And now the third tranche from alice to bob.
518+
currentTransferIdx += 1
519+
numTransfers += 1
520+
521+
sendResp, err = t.tapd.SendAsset(ctxt, &taprpc.SendAssetRequest{
522+
AddressesWithAmounts: []*taprpc.AddressWithAmount{
523+
{
524+
TapAddr: groupAddrBob.Encoded,
525+
Amount: thirdAsset.Amount,
526+
},
527+
},
528+
})
529+
require.NoError(t.t, err)
530+
t.Logf("Sent asset to group addr: %v", toJSON(t.t, sendResp))
531+
AssertAssetOutboundTransferWithOutputs(
532+
t.t, t.lndHarness.Miner().Client, t.tapd,
533+
sendResp.Transfer, [][]byte{thirdAssetID},
534+
[]uint64{thirdAsset.Amount}, currentTransferIdx,
535+
numTransfers, 1, true,
536+
)
537+
538+
AssertAddrEventByStatus(t.t, bobTapd, statusCompleted, numTransfers)
539+
540+
// We now make sure we can spend those assets again by sending
541+
// them from bob back to Alice, using an address with an amount.
542+
// this time, we'll send back all 3 tranches at once.
543+
groupAddrAlice, _ := NewAddrWithEventStream(
544+
t.t, t.tapd, &taprpc.NewAddrRequest{
545+
Amt: totalAmount,
546+
AddressVersion: addrV2,
547+
GroupKey: groupKey,
548+
},
549+
)
550+
551+
t.Logf("Got group addr: %v", toJSON(t.t, groupAddrAlice))
552+
553+
bobCurrentTransferIdx += 1
554+
bobNumTransfers += 1
555+
556+
sendResp, err = bobTapd.SendAsset(ctxt, &taprpc.SendAssetRequest{
557+
AddressesWithAmounts: []*taprpc.AddressWithAmount{
558+
{
559+
TapAddr: groupAddrAlice.Encoded,
560+
},
561+
},
562+
})
563+
require.NoError(t.t, err)
564+
565+
t.Logf("Sent asset to group addr: %v", toJSON(t.t, sendResp))
566+
567+
MineBlocks(t.t, t.lndHarness.Miner().Client, 1, 1)
568+
569+
AssertAddrEventByStatus(t.t, t.tapd, statusCompleted, bobNumTransfers)
570+
571+
// Now we send back from alice to bob again, but this time all at once
572+
// instead of individually.
573+
for i := 0; i < 4; i++ {
574+
currentTransferIdx += 1
575+
numTransfers += 1
576+
577+
sendResp, err = t.tapd.SendAsset(ctxt, &taprpc.SendAssetRequest{
578+
AddressesWithAmounts: []*taprpc.AddressWithAmount{
579+
{
580+
TapAddr: groupAddrBob.Encoded,
581+
Amount: totalAmount,
582+
},
583+
},
584+
})
585+
require.NoError(t.t, err)
586+
t.Logf("Sent asset to group addr: %v", toJSON(t.t, sendResp))
587+
MineBlocks(t.t, t.lndHarness.Miner().Client, 1, 1)
588+
AssertAddrEventByStatus(
589+
t.t, bobTapd, statusCompleted, numTransfers,
590+
)
591+
592+
// We again return all three tranches back to Alice.
593+
bobCurrentTransferIdx += 1
594+
bobNumTransfers += 1
595+
596+
addrReq := []*taprpc.AddressWithAmount{
597+
{
598+
TapAddr: groupAddrAlice.Encoded,
599+
},
600+
}
601+
sendResp, err = bobTapd.SendAsset(
602+
ctxt, &taprpc.SendAssetRequest{
603+
AddressesWithAmounts: addrReq,
604+
},
605+
)
606+
require.NoError(t.t, err)
607+
t.Logf("Sent asset to group addr: %v", toJSON(t.t, sendResp))
608+
MineBlocks(t.t, t.lndHarness.Miner().Client, 1, 1)
609+
AssertAddrEventByStatus(
610+
t.t, t.tapd, statusCompleted, bobNumTransfers,
611+
)
612+
}
613+
614+
// We now send each tranche back to bob individually, to make sure they
615+
// are spendable individually.
616+
amounts := []uint64{
617+
firstAsset.Amount, secondAsset.Amount, thirdAsset.Amount,
618+
}
619+
assetIDs := [][]byte{
620+
firstAssetID, secondAssetID, thirdAssetID,
621+
}
622+
for idx, amount := range amounts {
623+
currentTransferIdx += 1
624+
numTransfers += 1
625+
626+
sendResp, err = t.tapd.SendAsset(ctxt, &taprpc.SendAssetRequest{
627+
AddressesWithAmounts: []*taprpc.AddressWithAmount{
628+
{
629+
TapAddr: groupAddrBob.Encoded,
630+
Amount: amount,
631+
},
632+
},
633+
})
634+
require.NoError(t.t, err)
635+
t.Logf("Sent asset to group addr: %v", toJSON(t.t, sendResp))
636+
AssertAssetOutboundTransferWithOutputs(
637+
t.t, t.lndHarness.Miner().Client, t.tapd,
638+
sendResp.Transfer, [][]byte{assetIDs[idx]},
639+
[]uint64{amount}, currentTransferIdx, numTransfers, 1,
640+
true,
641+
)
642+
643+
AssertAddrEventByStatus(
644+
t.t, bobTapd, statusCompleted, numTransfers,
645+
)
646+
}
647+
}
648+
399649
// testAddressV2WithGroupKeyRestart tests that we can re-try and properly
400650
// continue the address v2 send process in various scenarios.
401651
func testAddressV2WithGroupKeyRestart(t *harnessTest) {

0 commit comments

Comments
 (0)