From 6236ce5cbdf097ab65db2b2fca7d99bdb99fc22e Mon Sep 17 00:00:00 2001 From: ffranr Date: Mon, 11 Dec 2023 14:59:56 +0000 Subject: [PATCH 1/3] rpcserver: improve error handling when querying for asset group given ID This commit adds code which handles `err != nil` which was previously absent. --- rpcserver.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/rpcserver.go b/rpcserver.go index 686800a81..8a357cfb3 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -2092,8 +2092,18 @@ func (r *rpcServer) BurnAsset(ctx context.Context, var groupKey *btcec.PublicKey assetGroup, err := r.cfg.TapAddrBook.QueryAssetGroup(ctx, assetID) - if err == nil && assetGroup.GroupKey != nil { + switch { + case err == nil && assetGroup.GroupKey != nil: + // We found the asset group, so we can use the group key to + // burn the asset. groupKey = &assetGroup.GroupPubKey + case errors.Is(err, address.ErrAssetGroupUnknown): + // We don't know the asset group, so we'll try to burn the + // asset using the asset ID only. + rpcsLog.Debug("Asset group key not found, asset may not be " + + "part of a group") + case err != nil: + return nil, fmt.Errorf("error querying asset group: %w", err) } fundResp, err := r.cfg.AssetWallet.FundBurn( From bbe373bffecec846108a3dc2931828ef7490729f Mon Sep 17 00:00:00 2001 From: ffranr Date: Mon, 11 Dec 2023 15:00:45 +0000 Subject: [PATCH 2/3] rpcserver: add asset burn logging This commit adds a few simple logging statements relating to the asset burn endpoint. --- rpcserver.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/rpcserver.go b/rpcserver.go index 8a357cfb3..148add54e 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -2063,6 +2063,8 @@ func (r *rpcServer) SendAsset(_ context.Context, func (r *rpcServer) BurnAsset(ctx context.Context, in *taprpc.BurnAssetRequest) (*taprpc.BurnAssetResponse, error) { + rpcsLog.Debug("Executing asset burn") + var assetID asset.ID switch { case len(in.GetAssetId()) > 0: @@ -2106,6 +2108,15 @@ func (r *rpcServer) BurnAsset(ctx context.Context, return nil, fmt.Errorf("error querying asset group: %w", err) } + var serializedGroupKey []byte + if groupKey != nil { + serializedGroupKey = groupKey.SerializeCompressed() + } + + rpcsLog.Infof("Burning asset (asset_id=%x, group_key=%x, "+ + "burn_amount=%d)", assetID[:], serializedGroupKey, + in.AmountToBurn) + fundResp, err := r.cfg.AssetWallet.FundBurn( ctx, &tapscript.FundingDescriptor{ ID: assetID, From 2f09b7e5aa65283fde57d60a87e1c1612eabb895 Mon Sep 17 00:00:00 2001 From: ffranr Date: Mon, 11 Dec 2023 15:18:00 +0000 Subject: [PATCH 3/3] itest: add test to ensure that an asset from an asset group can be burnt --- itest/burn_test.go | 110 +++++++++++++++++++++++++++++++++++++ itest/test_list_on_test.go | 4 ++ 2 files changed, 114 insertions(+) diff --git a/itest/burn_test.go b/itest/burn_test.go index 487cc2c8d..1558d5dce 100644 --- a/itest/burn_test.go +++ b/itest/burn_test.go @@ -2,6 +2,7 @@ package itest import ( "context" + "encoding/hex" taprootassets "github.com/lightninglabs/taproot-assets" "github.com/lightninglabs/taproot-assets/address" @@ -301,3 +302,112 @@ func testBurnAssets(t *harnessTest) { ) AssertBalanceByID(t.t, t.tapd, simpleGroupCollectGen.AssetId, 0) } + +// testBurnGroupedAssets tests that some amount of an asset from an asset group +// can be burnt successfully. +func testBurnGroupedAssets(t *harnessTest) { + var ( + ctxb = context.Background() + miner = t.lndHarness.Miner.Client + + firstMintReq = issuableAssets[0] + ) + + // We start off without any asset groups. + AssertNumGroups(t.t, t.tapd, 0) + + // Next, we mint a re-issuable asset, creating a new asset group. + firstMintResponses := MintAssetsConfirmBatch( + t.t, miner, t.tapd, []*mintrpc.MintAssetRequest{firstMintReq}, + ) + require.Len(t.t, firstMintResponses, 1) + + var ( + firstMintResp = firstMintResponses[0] + assetGroupKey = firstMintResp.AssetGroup.TweakedGroupKey + ) + + // Ensure that an asset group was created. + AssertNumGroups(t.t, t.tapd, 1) + + // Issue a further asset into the asset group. + simpleAssetsCopy := CopyRequests(simpleAssets) + secondMintReq := simpleAssetsCopy[0] + secondMintReq.Asset.Amount = 1010 + secondMintReq.Asset.GroupKey = assetGroupKey + secondMintReq.Asset.GroupedAsset = true + + secondMintResponses := MintAssetsConfirmBatch( + t.t, miner, t.tapd, + []*mintrpc.MintAssetRequest{secondMintReq}, + ) + require.Len(t.t, secondMintResponses, 1) + + // Ensure that we haven't created a new group. + AssertNumGroups(t.t, t.tapd, 1) + + secondMintResp := secondMintResponses[0] + + // Confirm that the minted asset group contains two assets. + assetGroups, err := t.tapd.ListGroups( + ctxb, &taprpc.ListGroupsRequest{}, + ) + require.NoError(t.t, err) + + encodedGroupKey := hex.EncodeToString(assetGroupKey) + assetGroup := assetGroups.Groups[encodedGroupKey] + require.Len(t.t, assetGroup.Assets, 2) + + // Burn some amount of the second asset. + var ( + burnAssetID = secondMintResp.AssetGenesis.AssetId + + preBurnAmt = secondMintResp.Amount + burnAmt = uint64(10) + postBurnAmt = preBurnAmt - burnAmt + ) + + burnResp, err := t.tapd.BurnAsset(ctxb, &taprpc.BurnAssetRequest{ + Asset: &taprpc.BurnAssetRequest_AssetId{ + AssetId: burnAssetID, + }, + AmountToBurn: burnAmt, + ConfirmationText: taprootassets.AssetBurnConfirmationText, + }) + require.NoError(t.t, err) + + burnRespJSON, err := formatProtoJSON(burnResp) + require.NoError(t.t, err) + t.Logf("Got response from burning %d units: %v", burnAmt, burnRespJSON) + + // Assert that the asset burn transfer occurred correctly. + AssertAssetOutboundTransferWithOutputs( + t.t, miner, t.tapd, burnResp.BurnTransfer, + burnAssetID, []uint64{postBurnAmt, burnAmt}, 0, 1, 2, true, + ) + + // Ensure that the burnt asset has the correct state. + burnedAsset := burnResp.BurnProof.Asset + allAssets, err := t.tapd.ListAssets( + ctxb, &taprpc.ListAssetRequest{IncludeSpent: true}, + ) + require.NoError(t.t, err) + AssertAssetStateByScriptKey( + t.t, allAssets.Assets, burnedAsset.ScriptKey, + AssetAmountCheck(burnedAsset.Amount), + AssetTypeCheck(burnedAsset.AssetGenesis.AssetType), + AssetScriptKeyIsLocalCheck(false), + AssetScriptKeyIsBurnCheck(true), + ) + + // Our asset balance should have been decreased by the burned amount. + AssertBalanceByID(t.t, t.tapd, burnAssetID, postBurnAmt) + + // Confirm that the minted asset group still contains two assets. + assetGroups, err = t.tapd.ListGroups(ctxb, &taprpc.ListGroupsRequest{}) + require.NoError(t.t, err) + + encodedGroupKey = hex.EncodeToString(assetGroupKey) + assetGroup = assetGroups.Groups[encodedGroupKey] + require.Len(t.t, assetGroup.Assets, 2) +} diff --git a/itest/test_list_on_test.go b/itest/test_list_on_test.go index 9d4d6a582..a7a9d52d1 100644 --- a/itest/test_list_on_test.go +++ b/itest/test_list_on_test.go @@ -187,6 +187,10 @@ var testCases = []*testCase{ name: "burn test", test: testBurnAssets, }, + { + name: "burn grouped assets", + test: testBurnGroupedAssets, + }, { name: "federation sync config", test: testFederationSyncConfig,