@@ -1320,6 +1320,87 @@ func (a *AssetStore) FetchManagedUTXOs(ctx context.Context) (
13201320 return managedUtxos , nil
13211321}
13221322
1323+ // ListZeroValueAnchors returns the set of managed anchor UTXOs that only
1324+ // contain tombstone/burn commitments and therefore have zero effective asset
1325+ // value.
1326+ //
1327+ // NOTE: This implements the tapfreighter.ZeroValueAnchorLister interface.
1328+ func (a * AssetStore ) ListZeroValueAnchors (ctx context.Context ) (
1329+ []* tapfreighter.ZeroValueAnchor , error ) {
1330+
1331+ managedUtxos , err := a .FetchManagedUTXOs (ctx )
1332+ if err != nil {
1333+ return nil , err
1334+ }
1335+
1336+ now := a .clock .Now ().UTC ()
1337+ anchors := make ([]* tapfreighter.ZeroValueAnchor , 0 )
1338+
1339+ for _ , utxo := range managedUtxos {
1340+ // Skip entries that are currently leased.
1341+ if len (utxo .LeaseOwner ) != 0 {
1342+ if utxo .LeaseExpiry .IsZero () || ! utxo .LeaseExpiry .Before (now ) {
1343+ continue
1344+ }
1345+ }
1346+
1347+ anchorPointBytes , err := encodeOutpoint (utxo .OutPoint )
1348+ if err != nil {
1349+ return nil , err
1350+ }
1351+
1352+ filter := QueryAssetFilters {
1353+ AnchorPoint : anchorPointBytes ,
1354+ Spent : sqlBool (false ),
1355+ Leased : sqlBool (false ),
1356+ Now : sql.NullTime {
1357+ Time : now ,
1358+ Valid : true ,
1359+ },
1360+ }
1361+
1362+ commitments , err := a .queryCommitments (ctx , filter )
1363+ switch {
1364+ case errors .Is (err , tapfreighter .ErrMatchingAssetsNotFound ):
1365+ continue
1366+ case err != nil :
1367+ return nil , err
1368+ }
1369+
1370+ if len (commitments ) == 0 {
1371+ continue
1372+ }
1373+
1374+ anchorCommitment := commitments [0 ].Commitment
1375+ assets := anchorCommitment .CommittedAssets ()
1376+ if len (assets ) == 0 {
1377+ continue
1378+ }
1379+
1380+ zeroValue := true
1381+ for _ , asset := range assets {
1382+ if asset .Amount > 0 && ! asset .IsBurn () {
1383+ zeroValue = false
1384+ break
1385+ }
1386+ }
1387+
1388+ if ! zeroValue {
1389+ continue
1390+ }
1391+
1392+ anchors = append (anchors , & tapfreighter.ZeroValueAnchor {
1393+ OutPoint : utxo .OutPoint ,
1394+ Value : utxo .OutputValue ,
1395+ InternalKey : utxo .InternalKey ,
1396+ Commitment : anchorCommitment ,
1397+ TapscriptSibling : append ([]byte (nil ), utxo .TapscriptSibling ... ),
1398+ })
1399+ }
1400+
1401+ return anchors , nil
1402+ }
1403+
13231404// FetchAssetProofsSizes fetches the sizes of the proofs in the db.
13241405func (a * AssetStore ) FetchAssetProofsSizes (
13251406 ctx context.Context ) ([]AssetProofSize , error ) {
@@ -2476,6 +2557,26 @@ func (a *AssetStore) LogPendingParcel(ctx context.Context,
24762557 }
24772558 }
24782559
2560+ for _ , zeroAnchor := range spend .ZeroValueAnchors {
2561+ anchorPointBytes , err := encodeOutpoint (zeroAnchor )
2562+ if err != nil {
2563+ return err
2564+ }
2565+
2566+ err = q .UpdateUTXOLease (ctx , UpdateUTXOLease {
2567+ LeaseOwner : finalLeaseOwner [:],
2568+ LeaseExpiry : sql.NullTime {
2569+ Time : finalLeaseExpiry .UTC (),
2570+ Valid : true ,
2571+ },
2572+ Outpoint : anchorPointBytes ,
2573+ })
2574+ if err != nil {
2575+ return fmt .Errorf ("unable to lease zero value " +
2576+ "anchor: %w" , err )
2577+ }
2578+ }
2579+
24792580 // Then the passive assets.
24802581 if len (spend .PassiveAssets ) > 0 {
24812582 if spend .PassiveAssetsAnchor == nil {
0 commit comments