taproot-assets icon indicating copy to clipboard operation
taproot-assets copied to clipboard

[bug]: ListUtxos not including tombstone asset

Open bitcoin-coder-bob opened this issue 7 months ago • 3 comments

Background

Began from this thread: https://lightningcommunity.slack.com/archives/C03B3556HQ8/p1740525100236419

ListUtxos does not include the 1k sat tombstone asset. The 1k sats essentially goes unaccounted for. The node does not appear to be aware that it has these 1k sats. By spending multiple asset utxos in one transaction, tombstones get generated but go unaccounted for with respect to the node creating the tombstone assets.

A simple example:

Node A has 5,000 sats and 5 utxos. 4 of the utxos are asset utxos and 1 it just a regular utxo not associated with any taproot asset. Node A spends all 5 utxos in one transaction, sending all of their asset units to Node B. Say the onchain fee incurred was 500 sats. We would expect that Node A has a net loss of 1,500 sats (500 sats from on chain fees and 1000 sat anchor for the asset paid to Node B) and after a block confirmation a new balance of 3,500 sats (the three 1k sat asset utxos plus 500 sats change). What appears to be happening is that the sats from these three tombstones will not be counted towards the sat balance, and lncli.WalletBalance will yield 500 sats instead of the expected 3,500.

I am not entirely sure how to distinguish if a taprpc.Asset is a tombstone. Presumably the IsSpent field would be true. I believe part of the fix may include: Inside func (r *rpcServer) ListUtxos the call to fetchRpcAssets should provide true for the includeSpent parameter. However this would then include all spent assets in the function response, a filter needs to be applied such that the response not all spent assets, just the ones that are tombstone assets.

Your environment

tapcli version 0.5.0-alpha commit=v0.5.0-4-g496a0413 litd version 0.14.0-alpha commit=v0.14.0-alpha-3-g8a2a711bf657ed5ce64e33374fbd9be8b9eea948-dirty

Steps to reproduce

Have a node where all of the asset units are in two different UTXOS. Spend the sum of these assets in one transaction. The result is that one output is the tombstone, and one is where you sent the asset units. Each utxo should have the 1k sat anchor. The 1k sat anchor from the tombstone will not show in the node's list of utxos from the rpc call to ListUtxos.

Expected behavior

The 1k sats from the tombstone should appear in ManagedUtxos in the response from ListUtxos. For accounting purposes, and for the node runner to know how many sats they have, ListUtxos should be including this 1k sat utxo. Additionally lncli.WalletBalance should be including these sats.

Actual behavior

The 1k sat tombstone appears to be missing in the list of the node's utxos. Both nodes involved in the transaction do not show it as a utxo they have control of. In reality, the node creating the tombstone asset has ownership over these 1k sats, but does not manifest this 1k sats in the response from ListUtxos, effectively producing a lower sat value to any caller of this rpc endpoint. lncli.WalletBalance is not including the sats from the tombstone assets.

bitcoin-coder-bob avatar Mar 31 '25 08:03 bitcoin-coder-bob

Thanks for the detailed report.

This is mostly "by design", until https://github.com/lightninglabs/taproot-assets/issues/514 is fully addressed.

You can identify tombstone assets by their amount and script key. If the amount is zero and the script key is the known NUMS key 027c79b9b26e463895eef5679d8558942c86c4ad2233adef01bc3e6d540b3653fe, it's a tombstone.

We don't include them in the ListUtxos outputs since there aren't any assets in them that can be spent, so it would mess with the coin selection.

You should be able to list all of the tapd-owned UTXOs in lnd with lncli walletbalance --account imported, which translates to lncli.WalletBalance(WalletBalanceRequest{Account: "imported"}).

I hope that helps for the moment.

guggero avatar Mar 31 '25 09:03 guggero

using lncli.WalletBalance(WalletBalanceRequest{Account: "imported"}) I get back 0 balance. Using lnrpc .ListUnspent(ctx, &lnrpc.ListUnspentRequest{Account: "imported", MinConfs: 0}) I get 0 items in the returned []*Utxo. Using walletrpc.ListUnspent(ctx, &walletrpc.ListUnspentRequest{Account: "imported", MinConfs: 0}) I get 0 items in the returned []*Utxo.

the tap owned utxo for the tombstone does not appear to be manifesting in the imported account. @guggero

bitcoin-coder-bob avatar Mar 31 '25 16:03 bitcoin-coder-bob

Ah, right, I was mistaken... The imported account will just show assets received through an address, and not the tombstones themselves. Yeah, we definitely need to address this somehow.

guggero avatar Mar 31 '25 16:03 guggero