|
28 | 28 | // ErrAssetMetaNotFound is returned when an asset meta is not found in
|
29 | 29 | // the database.
|
30 | 30 | ErrAssetMetaNotFound = fmt.Errorf("asset meta not found")
|
| 31 | + |
| 32 | + // ErrAssetGroupQueryFailed is returned when querying for an asset group |
| 33 | + // fails. |
| 34 | + ErrAssetGroupQueryFailed = fmt.Errorf("asset group query failed") |
| 35 | + |
| 36 | + // ErrAssetMetaQueryFailed is returned when querying for asset metadata |
| 37 | + // fails. |
| 38 | + ErrAssetMetaQueryFailed = fmt.Errorf("asset meta query failed") |
| 39 | + |
| 40 | + // ErrDelegationKeyQueryFailed is returned when querying for delegation |
| 41 | + // key fails. |
| 42 | + ErrDelegationKeyQueryFailed = fmt.Errorf("delegation key query failed") |
31 | 43 | )
|
32 | 44 |
|
33 | 45 | // AddrWithKeyInfo wraps a normal Taproot Asset struct with key descriptor
|
@@ -165,6 +177,12 @@ type Storage interface {
|
165 | 177 | // database.
|
166 | 178 | FetchAllAssetMeta(
|
167 | 179 | ctx context.Context) (map[asset.ID]*proof.MetaReveal, error)
|
| 180 | + |
| 181 | + // FetchInternalKeyLocator attempts to fetch the key locator information |
| 182 | + // for the given raw internal key. If the key cannot be found, then |
| 183 | + // ErrInternalKeyNotFound is returned. |
| 184 | + FetchInternalKeyLocator(ctx context.Context, |
| 185 | + rawKey *btcec.PublicKey) (keychain.KeyLocator, error) |
168 | 186 | }
|
169 | 187 |
|
170 | 188 | // KeyRing is used to create script and internal keys for Taproot Asset
|
@@ -841,3 +859,73 @@ func (b *Book) RemoveSubscriber(
|
841 | 859 |
|
842 | 860 | return nil
|
843 | 861 | }
|
| 862 | + |
| 863 | +// DelegationKeyChecker is used to verify that we control the delegation key |
| 864 | +// for a given asset, which is required for creating supply commitments. |
| 865 | +type DelegationKeyChecker interface { |
| 866 | + // HasDelegationKey checks if we control the delegation key for the |
| 867 | + // given asset ID. Returns true if we have the private key for the |
| 868 | + // asset's delegation key, false otherwise. |
| 869 | + HasDelegationKey(ctx context.Context, assetID asset.ID) (bool, error) |
| 870 | +} |
| 871 | + |
| 872 | +// HasDelegationKey checks if we control the delegation key for the given |
| 873 | +// asset ID. Returns true if we have the private key for the asset's |
| 874 | +// delegation key, false otherwise. |
| 875 | +// |
| 876 | +// NOTE: This is part of the DelegationKeyChecker interface. |
| 877 | +func (b *Book) HasDelegationKey(ctx context.Context, |
| 878 | + assetID asset.ID) (bool, error) { |
| 879 | + |
| 880 | + assetGroup, err := b.cfg.Store.QueryAssetGroupByID(ctx, assetID) |
| 881 | + if err != nil { |
| 882 | + return false, fmt.Errorf("%w: %w", ErrAssetGroupQueryFailed, |
| 883 | + err) |
| 884 | + } |
| 885 | + |
| 886 | + // If the asset doesn't have a group, it can't have a delegation key. So |
| 887 | + // we just return false here. |
| 888 | + if assetGroup == nil || assetGroup.GroupKey == nil { |
| 889 | + return false, nil |
| 890 | + } |
| 891 | + |
| 892 | + // Retrieve asset meta reveal for the asset ID. This will be used to |
| 893 | + // obtain the supply commitment delegation key. |
| 894 | + metaReveal, err := b.cfg.Store.FetchAssetMetaForAsset(ctx, assetID) |
| 895 | + if err != nil { |
| 896 | + return false, fmt.Errorf("%w: %w", ErrAssetMetaQueryFailed, err) |
| 897 | + } |
| 898 | + |
| 899 | + // If there's no meta reveal or delegation key, we can't control it. |
| 900 | + if metaReveal == nil || metaReveal.DelegationKey.IsNone() { |
| 901 | + return false, nil |
| 902 | + } |
| 903 | + |
| 904 | + delegationPubKey, err := metaReveal.DelegationKey.UnwrapOrErr( |
| 905 | + fmt.Errorf("delegation key not found for given asset"), |
| 906 | + ) |
| 907 | + if err != nil { |
| 908 | + return false, err |
| 909 | + } |
| 910 | + |
| 911 | + // Now that we have the delegation key, we'll see if we know of the |
| 912 | + // internal key locator. If we do, then this means that we were the ones |
| 913 | + // that created it in the first place. |
| 914 | + _, err = b.cfg.Store.FetchInternalKeyLocator(ctx, &delegationPubKey) |
| 915 | + switch { |
| 916 | + // If we get this error, then we don't control this delegation key. |
| 917 | + case errors.Is(err, ErrInternalKeyNotFound): |
| 918 | + return false, nil |
| 919 | + case err != nil: |
| 920 | + return false, fmt.Errorf("%w: %w", |
| 921 | + ErrDelegationKeyQueryFailed, err) |
| 922 | + } |
| 923 | + |
| 924 | + // If we reached this point, then we know that we control the delegation |
| 925 | + // key. |
| 926 | + return true, nil |
| 927 | +} |
| 928 | + |
| 929 | +// A compile-time assertion to ensure Book implements the DelegationKeyChecker |
| 930 | +// interface. |
| 931 | +var _ DelegationKeyChecker = (*Book)(nil) |
0 commit comments