Skip to content

Commit

Permalink
Merge pull request #979 from lightninglabs/dec_display_empty_meta
Browse files Browse the repository at this point in the history
taprpc: Set dec display when metadata is empty
  • Loading branch information
Roasbeef authored Jun 27, 2024
2 parents 1f59068 + d1c9c04 commit fc97efa
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 33 deletions.
81 changes: 49 additions & 32 deletions cmd/tapcli/assets.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package main

import (
"encoding/hex"
"encoding/json"
"fmt"
"math"
"os"
Expand Down Expand Up @@ -159,22 +158,14 @@ func parseAssetType(ctx *cli.Context) (taprpc.AssetType, error) {
}
}

func parseMetaType(metaType string,
metaBytes []byte) (taprpc.AssetMetaType, error) {

func parseMetaType(metaType string) (taprpc.AssetMetaType, error) {
switch metaType {
case "opaque":
fallthrough
case "blob":
return taprpc.AssetMetaType_META_TYPE_OPAQUE, nil

case "json":
// If JSON is selected, the bytes must be valid.
if !json.Valid(metaBytes) {
return 0, fmt.Errorf("invalid JSON for meta: %s",
metaBytes)
}

return taprpc.AssetMetaType_META_TYPE_JSON, nil

// Otherwise, this is a custom meta type, we may not understand it, but
Expand Down Expand Up @@ -232,24 +223,56 @@ func mintAsset(ctx *cli.Context) error {
}
}

metaTypeStr := ctx.String(assetMetaTypeName)
var (
metaTypeStr = ctx.String(assetMetaTypeName)
metaBytes = ctx.String(assetMetaBytesName)
metaFilePath = ctx.String(assetMetaFilePathName)
decDisplay = ctx.Uint64(assetDecimalDisplayName)
)

// Both the meta bytes and the meta path can be set.
if decDisplay > math.MaxUint32 {
return fmt.Errorf("decimal display must be a valid uint32")
}

metaType, err := parseMetaType(metaTypeStr)
if err != nil {
return fmt.Errorf("unable to parse meta type: %w", err)
}

// Before setting a non-empty meta, reject invalid combinations of
// metadata-related flags.
var assetMeta *taprpc.AssetMeta
switch {
case ctx.String(assetMetaBytesName) != "" &&
ctx.String(assetMetaFilePathName) != "":
return fmt.Errorf("meta bytes or meta file path cannot " +
"be both set")
case metaBytes != "" && metaFilePath != "":
return fmt.Errorf("meta bytes and meta file path cannot both " +
"be set")

case metaBytes == "" && metaFilePath == "":
switch metaType {
// Opaque is the default if the meta_type flag is not set, so
// having empty metadata is allowed.
case taprpc.AssetMetaType_META_TYPE_OPAQUE:
case taprpc.AssetMetaType_META_TYPE_JSON:
// Set only the metadata type; if present, the decimal
// display will be added as the actual metadata later.
// The minter will ultimately reject empty metadata.
assetMeta = &taprpc.AssetMeta{
Type: metaType,
}

// A custom meta type requires metadata to be present.
default:
return fmt.Errorf("metadata must be present for " +
"custom meta types")
}
}

// One of meta bytes or the meta path can be set.
switch {
case ctx.String(assetMetaBytesName) != "":
assetMeta = &taprpc.AssetMeta{
Data: []byte(ctx.String(assetMetaBytesName)),
}

assetMeta.Type, err = parseMetaType(metaTypeStr, assetMeta.Data)
if err != nil {
return fmt.Errorf("unable to parse meta type: %w", err)
Type: metaType,
}

case ctx.String(assetMetaFilePathName) != "":
Expand All @@ -263,11 +286,7 @@ func mintAsset(ctx *cli.Context) error {

assetMeta = &taprpc.AssetMeta{
Data: metaFileBytes,
}

assetMeta.Type, err = parseMetaType(metaTypeStr, assetMeta.Data)
if err != nil {
return fmt.Errorf("unable to parse meta type: %w", err)
Type: metaType,
}
}

Expand Down Expand Up @@ -304,12 +323,10 @@ func mintAsset(ctx *cli.Context) error {

resp, err := client.MintAsset(ctxc, &mintrpc.MintAssetRequest{
Asset: &mintrpc.MintAsset{
AssetType: assetType,
Name: ctx.String(assetTagName),
AssetMeta: assetMeta,
DecimalDisplay: uint32(
ctx.Uint64(assetDecimalDisplayName),
),
AssetType: assetType,
Name: ctx.String(assetTagName),
AssetMeta: assetMeta,
DecimalDisplay: uint32(decDisplay),
Amount: amount,
NewGroupedAsset: ctx.Bool(assetNewGroupedAssetName),
GroupedAsset: ctx.Bool(assetGroupedAssetName),
Expand Down
22 changes: 22 additions & 0 deletions itest/assertions.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,25 @@ func AssetVersionCheck(version taprpc.AssetVersion) AssetCheck {
}
}

// AssetDecimalDisplayCheck returns a check function that tests an asset's
// decimal display value. The check function requires that the rpc Asset has a
// non-nil decimal display value.
func AssetDecimalDisplayCheck(decDisplay uint32) AssetCheck {
return func(a *taprpc.Asset) error {
if a.DecimalDisplay == nil {
return fmt.Errorf("asset decimal display is nil")
}

if a.DecimalDisplay.DecimalDisplay != decDisplay {
return fmt.Errorf("unexpected asset decimal display, "+
"got %v wanted %v", a.DecimalDisplay,
decDisplay)
}

return nil
}
}

// GroupAssetsByName converts an unordered list of assets to a map of lists of
// assets, where all assets in a list have the same name.
func GroupAssetsByName(assets []*taprpc.Asset) map[string][]*taprpc.Asset {
Expand Down Expand Up @@ -1817,6 +1836,9 @@ func AssertAssetsMinted(t *testing.T, tapClient TapdClient,
AssetGroupTapscriptRootCheck(
assetRequest.Asset.GroupTapscriptRoot,
),
AssetDecimalDisplayCheck(
assetRequest.Asset.DecimalDisplay,
),
)

assetList = append(assetList, mintedAsset)
Expand Down
4 changes: 3 additions & 1 deletion itest/asset_meta_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,9 @@ func testMintAssetWithDecimalDisplayMetaField(t *harnessTest) {
require.ErrorContains(t.t, err, "decimal display does not match")

// If we update the decimal display to match the group anchor, minting
// should succeed.
// should succeed. We also unset the metadata to ensure that the decimal
// display is set as the sole JSON object if needed.
secondAssetReq.Asset.AssetMeta.Data = []byte{}
secondAssetReq.Asset.DecimalDisplay = firstAsset.DecimalDisplay
MintAssetsConfirmBatch(
t.t, t.lndHarness.Miner.Client, t.tapd,
Expand Down
3 changes: 3 additions & 0 deletions itest/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,9 @@ func FinalizeBatchUnconfirmed(t *testing.T, minerClient *rpcclient.Client,
AssetGroupTapscriptRootCheck(
assetRequest.Asset.GroupTapscriptRoot,
),
AssetDecimalDisplayCheck(
assetRequest.Asset.DecimalDisplay,
),
)
}

Expand Down
10 changes: 10 additions & 0 deletions rpcserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,16 @@ func (r *rpcServer) MintAsset(ctx context.Context,
Type: metaType,
}

// If a custom decimal display was requested correctly, but no
// metadata was provided, we'll set the metadata to an empty
// JSON object. The decimal display will be added as the only
// object.
if metaType == proof.MetaJson && req.Asset.DecimalDisplay != 0 {
if len(req.Asset.AssetMeta.Data) == 0 {
seedlingMeta.Data = []byte("{}")
}
}

err = seedlingMeta.Validate()
if err != nil {
return nil, err
Expand Down

0 comments on commit fc97efa

Please sign in to comment.