Skip to content

Commit 8af257f

Browse files
jharveybguggero
authored andcommitted
asset: add AssetCommitmentKey to AltLeaf interface
1 parent 9a48ca4 commit 8af257f

File tree

1 file changed

+62
-6
lines changed

1 file changed

+62
-6
lines changed

asset/asset.go

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,9 @@ var (
109109
// EmptyGenesis is the empty Genesis struct used for alt leaves.
110110
EmptyGenesis Genesis
111111

112+
// EmptyGenesisID is the ID of the empty genesis struct.
113+
EmptyGenesisID = EmptyGenesis.ID()
114+
112115
// NUMSBytes is the NUMs point we'll use for un-spendable script keys.
113116
// It was generated via a try-and-increment approach using the phrase
114117
// "taproot-assets" with SHA2-256. The code for the try-and-increment
@@ -127,6 +130,14 @@ var (
127130
// ErrUnknownVersion is returned when an asset with an unknown asset
128131
// version is being used.
129132
ErrUnknownVersion = errors.New("asset: unknown asset version")
133+
134+
// ErrUnwrapAssetID is returned when an asset ID cannot be unwrapped
135+
// from a Specifier.
136+
ErrUnwrapAssetID = errors.New("unable to unwrap asset ID")
137+
138+
// ErrDuplicateAltLeafKey is returned when a slice of AltLeaves contains
139+
// 2 or more AltLeaves with the same AssetCommitmentKey.
140+
ErrDuplicateAltLeafKey = errors.New("duplicate alt leaf key")
130141
)
131142

132143
const (
@@ -250,12 +261,6 @@ func DecodeGenesis(r io.Reader) (Genesis, error) {
250261
return gen, err
251262
}
252263

253-
var (
254-
// ErrUnwrapAssetID is an error type which is returned when an asset ID
255-
// cannot be unwrapped from a specifier.
256-
ErrUnwrapAssetID = errors.New("unable to unwrap asset ID")
257-
)
258-
259264
// Specifier is a type that can be used to specify an asset by its ID, its asset
260265
// group public key, or both.
261266
type Specifier struct {
@@ -2296,6 +2301,14 @@ type ChainAsset struct {
22962301
AnchorLeaseExpiry *time.Time
22972302
}
22982303

2304+
// LeafKeySet is a set of leaf keys.
2305+
type LeafKeySet = fn.Set[[32]byte]
2306+
2307+
// NewLeafKeySet creates a new leaf key set.
2308+
func NewLeafKeySet() LeafKeySet {
2309+
return fn.NewSet[[32]byte]()
2310+
}
2311+
22992312
// An AltLeaf is a type that is used to carry arbitrary data, and does not
23002313
// represent a Taproot asset. An AltLeaf can be used to anchor other protocols
23012314
// alongside Taproot Asset transactions.
@@ -2304,6 +2317,10 @@ type AltLeaf[T any] interface {
23042317
// the Copyable interface.
23052318
fn.Copyable[*T]
23062319

2320+
// AssetCommitmentKey is the key for an AltLeaf within an
2321+
// AssetCommitment.
2322+
AssetCommitmentKey() [32]byte
2323+
23072324
// ValidateAltLeaf ensures that an AltLeaf is valid.
23082325
ValidateAltLeaf() error
23092326

@@ -2389,6 +2406,45 @@ func (a *Asset) ValidateAltLeaf() error {
23892406
return nil
23902407
}
23912408

2409+
// ValidAltLeaves checks that a set of Assets are valid AltLeaves, and can be
2410+
// used to construct an AltCommitment. This requires that each AltLeaf has a
2411+
// unique AssetCommitmentKey.
2412+
func ValidAltLeaves(leaves []AltLeaf[Asset]) error {
2413+
leafKeys := NewLeafKeySet()
2414+
return AddLeafKeysVerifyUnique(leafKeys, leaves)
2415+
}
2416+
2417+
// AddLeafKeysVerifyUnique checks that a set of Assets are valid AltLeaves, and
2418+
// have unique AssetCommitmentKeys (unique among the given slice but also not
2419+
// colliding with any of the keys in the existingKeys set). If the leaves are
2420+
// valid, the function returns the updated set of keys.
2421+
func AddLeafKeysVerifyUnique(existingKeys LeafKeySet,
2422+
leaves []AltLeaf[Asset]) error {
2423+
2424+
for _, leaf := range leaves {
2425+
err := leaf.ValidateAltLeaf()
2426+
if err != nil {
2427+
return err
2428+
}
2429+
2430+
leafKey := leaf.AssetCommitmentKey()
2431+
if existingKeys.Contains(leafKey) {
2432+
return fmt.Errorf("%w: %x", ErrDuplicateAltLeafKey,
2433+
leafKey)
2434+
}
2435+
2436+
existingKeys.Add(leafKey)
2437+
}
2438+
2439+
return nil
2440+
}
2441+
2442+
// IsAltLeaf returns true if an Asset would be stored in the AltCommitment of
2443+
// a TapCommitment. It does not check if the Asset is a valid AltLeaf.
2444+
func (a *Asset) IsAltLeaf() bool {
2445+
return a.GroupKey == nil && a.Genesis == EmptyGenesis
2446+
}
2447+
23922448
// encodeAltLeafRecords determines the set of non-nil records to include when
23932449
// encoding an AltLeaf. Since the Genesis, Group Key, Amount, and Version fields
23942450
// are static, we can omit those fields.

0 commit comments

Comments
 (0)