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

[feature]: implement on-chain universe asset commitment verifier

Open Roasbeef opened this issue 9 months ago • 1 comments

Is your feature request related to a problem? Please describe.

This is related to #1451 and #1452.

With those two issues complete, we have the state machine that'll commit the new asset commitment into the chain. We'll then also have a new RPC layer to serve the new supply related trees, and also is meant to have a new on-chain merkle proof associated with each served leaf.

The final missing component is the on-chain verifier state machine.

Describe the solution you'd like

The on-chain verifier state machine keeps track of the set of synced grouped assets that will maintain a universe commitment on chain.

For each of those assets, it first needs to "sync" the on-chain portion of the commitment chain. This amounts to looking at the first issuance event, locating the pre-commitment output, then following that pre-commitment output all the way to the currently unspent commitment output.

Along the way, we may need to implement support for serving old roots to allow the verifier to check that the commitments have been created properly.

Once the final unspent commitment output is reached, then we've finishing sync mode and can now await for a future spend.

A rough state machine that can implement this looks something like:

stateDiagram-v2
    direction LR 

    [*] --> init
    init --> sync: initial issuance
    sync --> sync: commit spend
    sync --> idle: sync finished
    idle --> sync: commit spend

The general idea is that in the sync phase you await the spend of a pre-commitment (initial sync), or the commitment. You validate one step, then register for a spend. Once that spend is triggered you validate the next step. You terminate once the output you're validating remains unspent.

Roasbeef avatar Apr 08 '25 23:04 Roasbeef

Idk why the self loop to sync rendered all weird...

Roasbeef avatar Apr 08 '25 23:04 Roasbeef

Supply‑Commitment Verification—Clarifying Scope and Failure Modes

My understanding is that the verifier’s core job is simple: confirm that a supply‑commitment transaction is authenticated by the asset‑group minter.

What’s unclear to me is how we react when verification fails. My working assumption is that an invalid supply commitment does not invalidate any issued assets.

Given that assumption, two additional verifier duties described in this issue appear unnecessary:

1. Verifying superseded commitments

In my view, once a newer commitment exists for the same universe/asset group, earlier ones become irrelevant. Even if an older commitment is invalid, I don’t see any corrective action for a tapd node—just accept the most recent valid commitment and continue. Perhaps asset holders might only care about the latest snapshot.

Perhaps validating superseded supply commitments is necessary during catchup or syncing? But perhaps it only makes sense to sync the latest.

2. Enforcing an unbroken issuance and supply commitment tx chain

As I understand it, a minter can always mint a tranche outside the supply commitment tx chain. I don't see a way for the verifier to detect that gap, so chain‐integrity checks cannot be guaranteed. I suppose that any issuence/supply commitment tx chain can at least give a lower bound to the supply commitment issuance/burn count.

Supply commitments must be linked to their corresponding issuance anchor transaction for authentication—but perhaps that's the only requirement when traversing the transaction chain, without needing to reference every issuance event.


Proposed verifier scope

Summary of the previous section:

  • Invalid supply commitments do not retroactively affect issued assets.
  • Superseded supply commitments can be ignored during catch‑up.
  • An unbroken issuance/commitment chain cannot be enforced.

Therefore, in my view, the verifier’s only enforceable rule is to accept the latest commitment that is properly signed by the asset‑group minter (tied back to an issuance anchor tx). Clients can treat that commitment as a best‑effort global supply snapshot.

ffranr avatar May 09 '25 07:05 ffranr

What’s unclear to me is how we react when verification fails.

That's a good question. I guess it starts with: At what point do we actually attempt to verify those supply commitment proofs? I might be totally off here, but I imagine this to be a command the user runs to examine the "trustworthyness" of an issuer. So they would run tapcli universe audit-supply --group_key xyz. And the response would be either positive and give you the supply, burn, ignore information. Or it would be negative, telling the user where things didn't verify correctly.

I think you are correct in saying that the outcome of the verification doesn't change any behavior of the protocol itself. But again, I might have the wrong mental model here.

Even if an older commitment is invalid, I don’t see any corrective action for a tapd node

Yeah, I agree. The validity of the whole chain could just be an extra attribute that's returned from the audit command. So for example: the last proof is valid and here's the supply, but by the way, there were some invalid proofs in the chain.

a minter can always mint a tranche outside the supply commitment tx chain

With an unofficial or modified client, yes. But tapd would always validate that you're trying to mint into a universe commitment group and make you spend the previous commitment output, forcing you to have the chain be continuous (if you always have to spend a previous commitment output, you can't mint outside of the chain).

I guess what we could do is: Sync to one or more universes, collect all the issuance proofs for all tranches of a group. Then verify that each tranche is present in the supply commitment chain.

guggero avatar May 09 '25 16:05 guggero

What’s unclear to me is how we react when verification fails. My working assumption is that an invalid supply commitment does not invalidate any issued assets.

If you're implementing a very strict verifier, you'd reject that new tranche that was minted without following the rules. This is akin to a Bitcoin user doing invalidateblock to implement custom validation for a soft fork.

In my view, once a newer commitment exists for the same universe/asset group, earlier ones become irrelevant. Even if an older commitment is invalid, I don’t see any corrective action for a tapd node—just accept the most recent valid commitment and continue

A strict verifier would start from the genesis asset, then verify that all the rules have been followed, as the minted opted into them. If the rules haven't been followed, then they'd reject any violating tranche. If this is done in a wide spread manner, the assets that violated the rules are effectively invalid, as no one will accept them.


As I understand it, a minter can always mint a tranche outside the supply commitment tx chain. I don't see a way for the verifier to detect that gap, so chain‐integrity checks cannot be guaranteed.

If we add restrictions on asset inputs for a minting batch, then we can further constrain them. However that would add additional steps to a given minting flow, and we'd want to make sure these new steps weren't overly restrictive.

Ultimately the minter is opting into this, to be able to provide all holders with on-chain provenance of all the "official" actions they've done to increase transparency of operations.

The on-chain provenance also serves to provide another level of authentication to the proofs others may be serving related to the supply trees: there must be a merkle proof to the latest supply commitment. If you haven't validated that latest supply commitment, then you can't verify any proofs that purportedly originated from it.


Therefore, in my view, the verifier’s only enforceable rule is to accept the latest commitment that is properly signed by the asset‑group minter (tied back to an issuance anchor tx)

I think it depends entirely on how strict we're looking to make the verifier.

In Bitcoin there's the concept of a "velvet fork", wherein miners require a new commitment in the chain, but don't reject blocks that don't have this commitment. In contract for a normal soft fork, you do start to reject blocks that don't contain a commitment when ended (eg: segwit blocks w/ the witness merkle commitment are invalid).

My proposal in general is based on starting out as a velvet fork, then seeing what additional validation we should add along the way.

Validating the entire commitment chain gives the verifier a complete view into the history of the asset. You can see how the supply increased and shrunk over time, and can serve proofs for every part of that history (proof here is both the SMT layer, and also the Bitcoin header proof layer).

Roasbeef avatar May 09 '25 19:05 Roasbeef

So they would run tapcli universe audit-supply --group_key xyz. And the response would be either positive and give you the supply, burn, ignore information. Or it would be negative, telling the user where things didn't verify correctly.

In my mental model, it's an ongoing process. When you go to fetch the first genesis proof of an asset, you check if it's meant to have these on-chain proofs. If so, then you validate, but don't "finalize" the validation until you've also verified the set of on-chain proofs. To do that, you need to be able to access something that "claims" to be the raw log of operations. You can verify if that's correct or not as you can reproduce that initial commitment from it, then repeat that until you arrive at the unspent asset commitment.

Roasbeef avatar May 09 '25 19:05 Roasbeef