lightninglabs / lightninglabs/taproot-assets

Universe servers reject supply commitments carrying burn leaves

Open
#2,285 0 comments 0 reactions 1 assignee View on GitHub

@jtobin is already working on this.

Since Sep 8, 2026.

bug supply commit
Dominant language
Go
Stars
525
Forks
150
Avg merge
2d 15h
Merged PRs (30d)
31

Description

(Fable-generated. 'watcher-sites' is a development branch.)

Summary

A supply commitment that includes a burn leaf is rejected by every
receiving universe server with

supply commitment verification failed: burn leaf proof failed
verification: missing asset input(s): root_witness_prev_id=...

The burn leaf's proof is the transfer output's bare proof suffix. It
carries the burn output's state transition but no provenance for the
input that transition consumes, and the server verifies it with no
prior snapshot, so the transition has no inputs at all. The push can
never succeed. On main the failed push errors the supply-commit
state machine's finalize transition and stops the machine for that
group; on watcher-sites finalization is local and the push is an
outbox effect that retries forever at the capped backoff. In both
cases the burn never reaches the universe, and nothing surfaces it
beyond log lines.

Where

  • Sender: the chain porter records each burn output as an
    AssetBurn whose Proof is the output's ProofSuffix
    (tapfreighter/chain_porter.go, AssetBurn{Proof: o.ProofSuffix})
    and turns it into supplycommit.NewBurnEvent{BurnProof: burn.Proof}
    when emitting burn supply events. AdditionalInputs are only
    populated for the extra inputs of a multi-input transfer, never for
    the primary input, whose provenance is expected from the preceding
    proof in a proof file. A bare suffix has no preceding proof.
  • Receiver: universe/supplyverifier/verifier.go, verifyBurnLeaf,
    calls burnProof.Verify(ctx, nil, lookup, vCtx) with a nil prior
    snapshot. The state-transition check then finds no input matching
    the root witness's PrevID and fails with tapscript.ErrNoInputs
    ("missing asset input(s)").

Reproduction

  1. Mint a grouped asset with supply commitments enabled, with a
    remote universe server configured as a commitment push target.
  2. Burn part of it and let a commitment cycle run.
  3. The server's InsertSupplyCommit rejects the commitment with the
    error above; the sender's push logs the per-server failure.

The existing supply_commit_mint_burn itest does not catch this: it
asserts the burn subtree on the issuing node only and never fetches
the commitment from the universe server. The act-gating itest added
on watcher-sites (act_gated_supply_emissions) pins the burn on
the issuing node for the same reason, and documents this issue in its
commit message.

Impact

Any asset group that burns can no longer publish supply commitments
to its universe servers: the commitment carrying the burn is rejected,
and every later commitment builds on it. Verifiers on other nodes stop
seeing the group's supply.

Possible fixes

  • Sender-side: give the burn proof its own provenance. Embed the
    primary input's proof file in the burn proof's AdditionalInputs
    (or a dedicated field) when building the burn event, so the leaf
    verifies standalone like a v2 send fragment does. The proof is
    available at confirmation time from the input's file.
  • Receiver-side: resolve the burn's input from the server's own
    universe (the input's issuance or transfer leaf) and pass it as the
    prior snapshot to Verify; fail only when the input is genuinely
    unknown.
  • Either way, extend supply_commit_mint_burn to fetch the
    post-burn commitment from t.universeServer and assert the burn
    subtree there, so the push is actually exercised end to end.

Provenance

Pre-existing on main: the burn event has been built from the bare
output suffix since burn supply events were introduced. Found on
2026-09-07 while adding act-gating coverage for burn emissions on the
watcher-sites branch.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.