@@ -3702,24 +3702,6 @@ func (r *rpcServer) BurnAsset(ctx context.Context,
37023702
37033703 rpcsLog .Debug ("Executing asset burn" )
37043704
3705- var assetID asset.ID
3706- switch {
3707- case len (in .GetAssetId ()) > 0 :
3708- copy (assetID [:], in .GetAssetId ())
3709-
3710- case len (in .GetAssetIdStr ()) > 0 :
3711- assetIDBytes , err := hex .DecodeString (in .GetAssetIdStr ())
3712- if err != nil {
3713- return nil , fmt .Errorf ("error decoding asset ID: %w" ,
3714- err )
3715- }
3716-
3717- copy (assetID [:], assetIDBytes )
3718-
3719- default :
3720- return nil , fmt .Errorf ("asset ID must be specified" )
3721- }
3722-
37233705 if in .AmountToBurn == 0 {
37243706 return nil , fmt .Errorf ("amount to burn must be specified" )
37253707 }
@@ -3729,36 +3711,120 @@ func (r *rpcServer) BurnAsset(ctx context.Context,
37293711 "accidental asset burns" )
37303712 }
37313713
3732- var groupKey * btcec.PublicKey
3733- assetGroup , err := r .cfg .TapAddrBook .QueryAssetGroupByID (ctx , assetID )
3714+ var (
3715+ assetID * asset.ID
3716+ groupKey * btcec.PublicKey
3717+ err error
3718+ )
3719+
3720+ // TODO(darioAnongba): Remove this switch once the deprecated asset
3721+ // field is removed. Keep only the AssetSpecifier case.
3722+ // Added in v0.8.0.
37343723 switch {
3735- case err == nil && assetGroup .GroupKey != nil :
3736- // We found the asset group, so we can use the group key to
3737- // burn the asset.
3738- groupKey = & assetGroup .GroupPubKey
3724+ case in .Asset != nil :
3725+ rpcsLog .Warnf ("using deprecated asset field, please use " +
3726+ "asset_specifier instead" )
37393727
3740- case errors .Is (err , address .ErrAssetGroupUnknown ):
3741- // We don't know the asset group, so we'll try to burn the
3742- // asset using the asset ID only.
3743- rpcsLog .Debug ("Asset group key not found, asset may not be " +
3744- "part of a group" )
3728+ switch {
3729+ case len (in .GetAssetId ()) > 0 :
3730+ var assetIdBytes [32 ]byte
3731+ copy (assetIdBytes [:], in .GetAssetId ())
3732+ id := asset .ID (assetIdBytes )
3733+ assetID = & id
3734+
3735+ case len (in .GetAssetIdStr ()) > 0 :
3736+ assetIDBytes , err := hex .DecodeString (
3737+ in .GetAssetIdStr (),
3738+ )
3739+ if err != nil {
3740+ return nil , fmt .Errorf ("error decoding " +
3741+ "asset ID: %w" ,
3742+ err )
3743+ }
37453744
3746- case err != nil :
3747- return nil , fmt .Errorf ("error querying asset group: %w" , err )
3748- }
3745+ var id asset.ID
3746+ copy (id [:], assetIDBytes )
3747+ assetID = & id
3748+
3749+ default :
3750+ return nil , fmt .Errorf ("asset ID must be specified" )
3751+ }
3752+
3753+ case in .AssetSpecifier != nil :
3754+ assetID , groupKey , err = parseAssetSpecifier (
3755+ in .AssetSpecifier .GetId (),
3756+ "" ,
3757+ in .AssetSpecifier .GetGroupKey (),
3758+ "" ,
3759+ )
3760+ if err != nil {
3761+ return nil , fmt .Errorf ("unable to parse asset " +
3762+ "specifier: %w" , err )
3763+ }
37493764
3750- var serializedGroupKey []byte
3751- if groupKey != nil {
3752- serializedGroupKey = groupKey .SerializeCompressed ()
3765+ default :
3766+ return nil , fmt .Errorf ("asset_specifier field unset" )
37533767 }
37543768
3755- rpcsLog .Infof ("Burning asset (asset_id=%x, group_key=%x, " +
3756- "burn_amount=%d)" , assetID [:], serializedGroupKey ,
3757- in .AmountToBurn )
3769+ // Handle different scenarios based on what was provided:
3770+ // 1. If only assetID is provided, look up the group key.
3771+ // 2. If only groupKey is provided, use it directly
3772+ // 3. If both are provided, validate consistency.
3773+ switch {
3774+ case assetID != nil && groupKey == nil :
3775+ assetGroup , err := r .cfg .TapAddrBook .QueryAssetGroupByID (
3776+ ctx , * assetID ,
3777+ )
3778+ switch {
3779+ case err == nil && assetGroup .GroupKey != nil :
3780+ groupKey = & assetGroup .GroupPubKey
3781+
3782+ case errors .Is (err , address .ErrAssetGroupUnknown ):
3783+ rpcsLog .Trace ("Asset group key not found, asset " +
3784+ "may not be part of a group" )
3785+
3786+ case err != nil :
3787+ return nil , fmt .Errorf ("error querying asset " +
3788+ "group: %w" , err )
3789+ }
3790+
3791+ case assetID != nil && groupKey != nil :
3792+ assetGroup , err := r .cfg .TapAddrBook .QueryAssetGroupByID (
3793+ ctx , * assetID ,
3794+ )
3795+ switch {
3796+ case err == nil && assetGroup .GroupKey != nil :
3797+ if ! groupKey .IsEqual (& assetGroup .GroupPubKey ) {
3798+ return nil , fmt .Errorf ("inconsistent asset " +
3799+ "ID for given group key" )
3800+ }
3801+
3802+ case errors .Is (err , address .ErrAssetGroupUnknown ):
3803+ return nil , fmt .Errorf ("asset is not part of a group" )
3804+
3805+ case err != nil :
3806+ return nil , fmt .Errorf ("error querying asset " +
3807+ "group: %w" , err )
3808+ }
3809+
3810+ case assetID == nil && groupKey != nil :
3811+ // Only group key provided - use it directly
3812+
3813+ default :
3814+ // Should be unreachable by assertion.
3815+ return nil , fmt .Errorf ("invalid asset specifier state" )
3816+ }
37583817
3759- assetSpecifier := asset .NewSpecifierOptionalGroupPubKey (
3760- assetID , groupKey ,
3818+ assetSpecifier , err := asset .NewSpecifier (
3819+ assetID , groupKey , nil , true ,
37613820 )
3821+ if err != nil {
3822+ return nil , fmt .Errorf ("unable to create asset specifier: %w" ,
3823+ err )
3824+ }
3825+
3826+ rpcsLog .Infof ("Burning asset (asset_specifier=%v, burn_amount=%d)" ,
3827+ assetSpecifier , in .AmountToBurn )
37623828
37633829 fundResp , err := r .cfg .AssetWallet .FundBurn (
37643830 ctx , & tapsend.FundingDescriptor {
@@ -3770,17 +3836,13 @@ func (r *rpcServer) BurnAsset(ctx context.Context,
37703836 return nil , fmt .Errorf ("error funding burn: %w" , err )
37713837 }
37723838
3773- // We don't support burning by group key yet, so we only expect a single
3774- // vPacket (which implies a single asset ID is involved).
3775- if len (fundResp .VPackets ) > 1 {
3776- return nil , fmt .Errorf ("only one packet supported" )
3777- }
3778-
3779- // Now we can sign the packet and send it to the chain.
3780- vPkt := fundResp .VPackets [0 ]
3781- _ , err = r .cfg .AssetWallet .SignVirtualPacket (ctx , vPkt )
3782- if err != nil {
3783- return nil , fmt .Errorf ("error signing packet: %w" , err )
3839+ // Sign all virtual packets created for this burn
3840+ // (may be more than one when burning by group key).
3841+ for _ , vPkt := range fundResp .VPackets {
3842+ _ , err = r .cfg .AssetWallet .SignVirtualPacket (ctx , vPkt )
3843+ if err != nil {
3844+ return nil , fmt .Errorf ("error signing packet: %w" , err )
3845+ }
37843846 }
37853847
37863848 resp , err := r .cfg .ChainPorter .RequestShipment (
@@ -3798,28 +3860,29 @@ func (r *rpcServer) BurnAsset(ctx context.Context,
37983860 err )
37993861 }
38003862
3801- var burnProof * taprpc.DecodedProof
3802- for idx := range resp .Outputs {
3803- vOut := vPkt .Outputs [idx ]
3804- tOut := resp .Outputs [idx ]
3805- if vOut .Asset .IsBurn () {
3806- p , err := proof .Decode (tOut .ProofSuffix )
3807- if err != nil {
3808- return nil , fmt .Errorf ("error decoding " +
3809- "burn proof: %w" , err )
3810- }
3863+ var burnProofs []* taprpc.DecodedProof
3864+ for _ , tOut := range resp .Outputs {
3865+ p , err := proof .Decode (tOut .ProofSuffix )
3866+ if err != nil {
3867+ return nil , fmt .Errorf ("error decoding burn proof: %w" ,
3868+ err )
3869+ }
38113870
3812- burnProof , err = r .marshalProof (ctx , p , true , false )
3813- if err != nil {
3814- return nil , fmt .Errorf ("error decoding " +
3815- "burn proof: %w" , err )
3816- }
3871+ if ! p .Asset .IsBurn () {
3872+ continue
3873+ }
3874+
3875+ burnProof , err := r .marshalProof (ctx , p , true , false )
3876+ if err != nil {
3877+ return nil , fmt .Errorf ("error decoding burn proof: %w" ,
3878+ err )
38173879 }
3880+ burnProofs = append (burnProofs , burnProof )
38183881 }
38193882
38203883 return & taprpc.BurnAssetResponse {
38213884 BurnTransfer : parcel ,
3822- BurnProof : burnProof ,
3885+ BurnProofs : burnProofs ,
38233886 }, nil
38243887}
38253888
@@ -8002,19 +8065,14 @@ func parseAssetSpecifier(reqAssetID []byte, reqAssetIDStr string,
80028065 reqGroupKey []byte , reqGroupKeyStr string ) (* asset.ID , * btcec.PublicKey ,
80038066 error ) {
80048067
8005- // Attempt to decode the asset specifier from the RPC request. In cases
8006- // where both the asset ID and asset group key are provided, we will
8007- // give precedence to the asset ID due to its higher level of
8008- // specificity.
80098068 var (
80108069 assetID * asset.ID
80118070 groupKey * btcec.PublicKey
80128071 err error
80138072 )
80148073
8015- switch {
8016- // Parse the asset ID if it's set.
8017- case len (reqAssetID ) > 0 :
8074+ // Parse the asset ID if it's set (either as bytes or string).
8075+ if len (reqAssetID ) > 0 {
80188076 if len (reqAssetID ) != sha256 .Size {
80198077 return nil , nil , fmt .Errorf ("asset ID must be 32 bytes" )
80208078 }
@@ -8023,46 +8081,41 @@ func parseAssetSpecifier(reqAssetID []byte, reqAssetIDStr string,
80238081 copy (assetIdBytes [:], reqAssetID )
80248082 id := asset .ID (assetIdBytes )
80258083 assetID = & id
8026-
8027- case len (reqAssetIDStr ) > 0 :
8084+ } else if len (reqAssetIDStr ) > 0 {
80288085 assetIDBytes , err := hex .DecodeString (reqAssetIDStr )
80298086 if err != nil {
8030- return nil , nil , fmt .Errorf ("error decoding asset " +
8031- "ID: %w" , err )
8032- }
8033-
8034- if len (assetIDBytes ) != sha256 .Size {
8035- return nil , nil , fmt .Errorf ("asset ID must be 32 bytes" )
8087+ return nil , nil , fmt .Errorf ("error decoding " +
8088+ "asset ID: %w" , err )
80368089 }
80378090
80388091 var id asset.ID
80398092 copy (id [:], assetIDBytes )
80408093 assetID = & id
8094+ }
80418095
8042- // Parse the group key if it's set.
8043- case len (reqGroupKey ) > 0 :
8096+ // Parse the group key if it's set (either as bytes or string) .
8097+ if len (reqGroupKey ) > 0 {
80448098 groupKey , err = btcec .ParsePubKey (reqGroupKey )
80458099 if err != nil {
80468100 return nil , nil , fmt .Errorf ("error parsing group " +
80478101 "key: %w" , err )
80488102 }
8049-
8050- case len (reqGroupKeyStr ) > 0 :
8103+ } else if len (reqGroupKeyStr ) > 0 {
80518104 groupKeyBytes , err := hex .DecodeString (reqGroupKeyStr )
80528105 if err != nil {
8053- return nil , nil , fmt .Errorf ("error decoding group " +
8054- "key: %w" , err )
8106+ return nil , nil , fmt .Errorf ("error decoding " +
8107+ "group key: %w" , err )
80558108 }
80568109
80578110 groupKey , err = btcec .ParsePubKey (groupKeyBytes )
80588111 if err != nil {
80598112 return nil , nil , fmt .Errorf ("error parsing group " +
80608113 "key: %w" , err )
80618114 }
8115+ }
80628116
8063- default :
8064- // At this point, we know that neither the asset ID nor the
8065- // group key are specified. Return an error.
8117+ // Validate that at least one is specified.
8118+ if assetID == nil && groupKey == nil {
80668119 return nil , nil , fmt .Errorf ("either asset ID or asset group " +
80678120 "key must be specified" )
80688121 }
0 commit comments