Skip to content

Commit 45210dc

Browse files
committed
tapgarden: add delegation key filtering for mint supply commits
This commit enhances the BatchCaretaker to filter mint events based on delegation key ownership. The sendSupplyCommitEvents method now uses functional filtering to ensure supply commitment events are only sent for assets where we control the delegation key. Similar to the burn event filtering in tapfreighter, this change ensures the caretaker respects delegation authority when creating supply proofs for newly minted assets. The filtering happens early in the process to avoid unnecessary proof construction and event submission for assets we're not authorized to manage.
1 parent ab74541 commit 45210dc

File tree

1 file changed

+119
-0
lines changed

1 file changed

+119
-0
lines changed

tapgarden/caretaker.go

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,6 +1148,17 @@ func (b *BatchCaretaker) stateStep(currentState BatchState) (BatchState, error)
11481148
return 0, fmt.Errorf("unable to confirm batch: %w", err)
11491149
}
11501150

1151+
// Send supply commitment events for all minted assets before
1152+
// finalizing the batch. This ensures that supply commitments
1153+
// are tracked before the batch is considered complete.
1154+
err = b.sendSupplyCommitEvents(
1155+
ctx, anchorAssets, nonAnchorAssets, mintingProofs,
1156+
)
1157+
if err != nil {
1158+
return 0, fmt.Errorf("unable to send supply commit "+
1159+
"events: %w", err)
1160+
}
1161+
11511162
// Now that we've confirmed the batch, we'll hand over the
11521163
// proofs to the re-org watcher.
11531164
if err := b.cfg.ProofWatcher.WatchProofs(
@@ -1432,6 +1443,114 @@ func GenHeaderVerifier(ctx context.Context,
14321443
}
14331444
}
14341445

1446+
// sendSupplyCommitEvents sends supply commitment events for all minted assets
1447+
// in the batch to track them in the supply commitment state machine.
1448+
func (b *BatchCaretaker) sendSupplyCommitEvents(ctx context.Context,
1449+
anchorAssets, nonAnchorAssets []*asset.Asset,
1450+
mintingProofs proof.AssetProofs) error {
1451+
1452+
// If no supply commit manager is configured, skip this step.
1453+
if b.cfg.MintCommitter == nil {
1454+
return nil
1455+
}
1456+
1457+
// If no delegation key checker is configured, skip this step.
1458+
if b.cfg.DelegationKeyChecker == nil {
1459+
return nil
1460+
}
1461+
1462+
// Combine all assets for processing.
1463+
allAssets := append(anchorAssets, nonAnchorAssets...)
1464+
1465+
// Filter out assets where we don't control the delegation key.
1466+
assetsWithDelegation := fn.Filter(allAssets, func(a *asset.Asset) bool {
1467+
hasDelegationKey, err := b.cfg.DelegationKeyChecker.HasDelegationKey(
1468+
ctx, a.ID(),
1469+
)
1470+
if err != nil {
1471+
log.Debugf("Error checking delegation key for asset %x: %v",
1472+
a.ID(), err)
1473+
return false
1474+
}
1475+
if !hasDelegationKey {
1476+
log.Debugf("Skipping supply commit event for asset %x: "+
1477+
"delegation key not controlled locally",
1478+
a.ID())
1479+
}
1480+
return hasDelegationKey
1481+
})
1482+
1483+
for _, mintedAsset := range assetsWithDelegation {
1484+
scriptKey := asset.ToSerialized(mintedAsset.ScriptKey.PubKey)
1485+
mintingProof, ok := mintingProofs[scriptKey]
1486+
if !ok {
1487+
return fmt.Errorf("missing minting proof for asset "+
1488+
"with script key %x", scriptKey[:])
1489+
}
1490+
1491+
// Create the universe leaf key and proof for this asset.
1492+
universeKey := universe.BaseLeafKey{
1493+
OutPoint: mintedAsset.Genesis.FirstPrevOut,
1494+
ScriptKey: &mintedAsset.ScriptKey,
1495+
}
1496+
1497+
// Convert the proof to bytes for use with DecodeFile and universe.Leaf.
1498+
proofBlob, err := proof.EncodeAsProofFile(mintingProof)
1499+
if err != nil {
1500+
return fmt.Errorf("unable to encode proof as file: %w", err)
1501+
}
1502+
1503+
// Parse the proof to create the universe leaf.
1504+
proofFile, err := proof.DecodeFile(proofBlob)
1505+
if err != nil {
1506+
return fmt.Errorf("unable to decode proof file: %w", err)
1507+
}
1508+
1509+
// Get the leaf proof from the proof file.
1510+
leafProof, err := proofFile.LastProof()
1511+
if err != nil {
1512+
return fmt.Errorf("unable to get leaf proof: %w", err)
1513+
}
1514+
1515+
universeLeaf := universe.Leaf{
1516+
GenesisWithGroup: universe.GenesisWithGroup{
1517+
Genesis: mintedAsset.Genesis,
1518+
GroupKey: mintedAsset.GroupKey,
1519+
},
1520+
RawProof: proofBlob,
1521+
Asset: &leafProof.Asset,
1522+
Amt: mintedAsset.Amount,
1523+
}
1524+
1525+
// Create the unique leaf key for universe registration.
1526+
uniqueLeafKey := universe.AssetLeafKey{
1527+
BaseLeafKey: universeKey,
1528+
AssetID: mintedAsset.ID(),
1529+
}
1530+
1531+
// Send the mint event to the supply commit manager.
1532+
1533+
// Determine the asset specifier for this asset.
1534+
assetSpec := asset.NewSpecifierOptionalGroupKey(
1535+
mintedAsset.ID(), mintedAsset.GroupKey,
1536+
)
1537+
1538+
// Send the mint event to the supply commit manager.
1539+
err = b.cfg.MintCommitter.SendMintEvent(
1540+
ctx, assetSpec, uniqueLeafKey, universeLeaf,
1541+
)
1542+
if err != nil {
1543+
return fmt.Errorf("unable to send mint event for "+
1544+
"asset %x: %w", mintedAsset.ID(), err)
1545+
}
1546+
1547+
log.Debugf("Sent supply commit mint event for asset %x",
1548+
mintedAsset.ID())
1549+
}
1550+
1551+
return nil
1552+
}
1553+
14351554
// assetGroupCacheSize is the size of the cache for group keys.
14361555
const assetGroupCacheSize = 10000
14371556

0 commit comments

Comments
 (0)