Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add asset group burn itest, logging, and missing error handling #732

Merged
merged 3 commits into from
Dec 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 110 additions & 0 deletions itest/burn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package itest

import (
"context"
"encoding/hex"

taprootassets "github.com/lightninglabs/taproot-assets"
"github.com/lightninglabs/taproot-assets/address"
Expand Down Expand Up @@ -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) {
guggero marked this conversation as resolved.
Show resolved Hide resolved
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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we could (in a future PR) extend this. I am curious what would happen if we burned all the amount from the second mint. Would this then have to be require.Len(t.t, assetGroup.Assets, 1) ?

}
4 changes: 4 additions & 0 deletions itest/test_list_on_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,10 @@ var testCases = []*testCase{
name: "burn test",
test: testBurnAssets,
},
{
name: "burn grouped assets",
test: testBurnGroupedAssets,
},
{
name: "federation sync config",
test: testFederationSyncConfig,
Expand Down
23 changes: 22 additions & 1 deletion rpcserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -2092,10 +2094,29 @@ 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)
}

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,
Expand Down