Skip to content

Commit 2f518d2

Browse files
authored
Merge pull request #1464 from Roasbeef/asset-commitment-creator
universe/supplycommit: create new state machine responsible for maintaining the supply commitment for an asset
2 parents 41be822 + 82f4ee3 commit 2f518d2

File tree

11 files changed

+3850
-72
lines changed

11 files changed

+3850
-72
lines changed

asset/generators.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ var (
8080
})
8181
ScriptKeyGen = rapid.Custom(func(t *rapid.T) ScriptKey {
8282
return ScriptKey{
83-
PubKey: MaybePubKeyGen.Draw(t, "pubkey"),
83+
PubKey: PubKeyGen.Draw(t, "pubkey"),
8484
TweakedScriptKey: rapid.Ptr(
8585
TweakedScriptKeyGen, true,
8686
).Draw(t, "tweaked_script_key"),

go.mod

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ require (
99
github.com/btcsuite/btcd/btcutil/psbt v1.1.10
1010
github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0
1111
github.com/btcsuite/btclog v0.0.0-20241003133417-09c4e92e319c
12-
github.com/btcsuite/btclog/v2 v2.0.1-0.20250110154127-3ae4bf1cb318
13-
github.com/btcsuite/btcwallet v0.16.13
12+
github.com/btcsuite/btclog/v2 v2.0.1-0.20250602222548-9967d19bb084
13+
github.com/btcsuite/btcwallet v0.16.14
1414
github.com/btcsuite/btcwallet/wallet/txsizes v1.2.5
1515
github.com/btcsuite/btcwallet/wtxmgr v1.5.6
1616
github.com/caddyserver/certmagic v0.17.2
@@ -30,11 +30,11 @@ require (
3030
github.com/lightninglabs/lndclient v0.19.0-7
3131
github.com/lightninglabs/neutrino/cache v1.1.2
3232
github.com/lightninglabs/taproot-assets/taprpc v1.0.7
33-
github.com/lightningnetwork/lnd v0.19.0-beta
33+
github.com/lightningnetwork/lnd v0.19.0-beta.rc5.0.20250611041824-9e9524766c8a
3434
github.com/lightningnetwork/lnd/cert v1.2.2
3535
github.com/lightningnetwork/lnd/clock v1.1.1
3636
github.com/lightningnetwork/lnd/fn/v2 v2.0.8
37-
github.com/lightningnetwork/lnd/tlv v1.3.1
37+
github.com/lightningnetwork/lnd/tlv v1.3.2
3838
github.com/lightningnetwork/lnd/tor v1.1.6
3939
github.com/ory/dockertest/v3 v3.10.0
4040
github.com/pmezard/go-difflib v1.0.0
@@ -131,7 +131,7 @@ require (
131131
github.com/lightningnetwork/lnd/healthcheck v1.2.6 // indirect
132132
github.com/lightningnetwork/lnd/kvdb v1.4.16 // indirect
133133
github.com/lightningnetwork/lnd/queue v1.1.1 // indirect
134-
github.com/lightningnetwork/lnd/sqldb v1.0.9 // indirect
134+
github.com/lightningnetwork/lnd/sqldb v1.0.10 // indirect
135135
github.com/lightningnetwork/lnd/ticker v1.1.1 // indirect
136136
github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796 // indirect
137137
github.com/mattn/go-isatty v0.0.20 // indirect

go.sum

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -666,11 +666,11 @@ github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0/go.mod h1:7SFka0XMvUgj3hfZtyd
666666
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
667667
github.com/btcsuite/btclog v0.0.0-20241003133417-09c4e92e319c h1:4HxD1lBUGUddhzgaNgrCPsFWd7cGYNpeFUgd9ZIgyM0=
668668
github.com/btcsuite/btclog v0.0.0-20241003133417-09c4e92e319c/go.mod h1:w7xnGOhwT3lmrS4H3b/D1XAXxvh+tbhUm8xeHN2y3TQ=
669-
github.com/btcsuite/btclog/v2 v2.0.1-0.20250110154127-3ae4bf1cb318 h1:oCjIcinPt7XQ644MP/22JcjYEC84qRc3bRBH0d7Hhd4=
670-
github.com/btcsuite/btclog/v2 v2.0.1-0.20250110154127-3ae4bf1cb318/go.mod h1:XItGUfVOxotJL8kkuk2Hj3EVow5KCugXl3wWfQ6K0AE=
669+
github.com/btcsuite/btclog/v2 v2.0.1-0.20250602222548-9967d19bb084 h1:y3bvkt8ki0KX35eUEU8XShRHusz1S+55QwXUTmxn888=
670+
github.com/btcsuite/btclog/v2 v2.0.1-0.20250602222548-9967d19bb084/go.mod h1:XItGUfVOxotJL8kkuk2Hj3EVow5KCugXl3wWfQ6K0AE=
671671
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
672-
github.com/btcsuite/btcwallet v0.16.13 h1:JGu+wrihQ0I00ODb3w92JtBPbrHxZhbcvU01O+e+lKw=
673-
github.com/btcsuite/btcwallet v0.16.13/go.mod h1:H6dfoZcWPonM2wbVsR2ZBY0PKNZKdQyLAmnX8vL9JFA=
672+
github.com/btcsuite/btcwallet v0.16.14 h1:CofysgmI1ednkLsXontAdBoXJkbiim7unXnFKhLLjnE=
673+
github.com/btcsuite/btcwallet v0.16.14/go.mod h1:H6dfoZcWPonM2wbVsR2ZBY0PKNZKdQyLAmnX8vL9JFA=
674674
github.com/btcsuite/btcwallet/wallet/txauthor v1.3.5 h1:Rr0njWI3r341nhSPesKQ2JF+ugDSzdPoeckS75SeDZk=
675675
github.com/btcsuite/btcwallet/wallet/txauthor v1.3.5/go.mod h1:+tXJ3Ym0nlQc/iHSwW1qzjmPs3ev+UVWMbGgfV1OZqU=
676676
github.com/btcsuite/btcwallet/wallet/txrules v1.2.2 h1:YEO+Lx1ZJJAtdRrjuhXjWrYsmAk26wLTlNzxt2q0lhk=
@@ -1149,8 +1149,8 @@ github.com/lightninglabs/protobuf-go-hex-display v1.34.2-hex-display h1:w7FM5LH9
11491149
github.com/lightninglabs/protobuf-go-hex-display v1.34.2-hex-display/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
11501150
github.com/lightningnetwork/lightning-onion v1.2.1-0.20240712235311-98bd56499dfb h1:yfM05S8DXKhuCBp5qSMZdtSwvJ+GFzl94KbXMNB1JDY=
11511151
github.com/lightningnetwork/lightning-onion v1.2.1-0.20240712235311-98bd56499dfb/go.mod h1:c0kvRShutpj3l6B9WtTsNTBUtjSmjZXbJd9ZBRQOSKI=
1152-
github.com/lightningnetwork/lnd v0.19.0-beta h1:/8i2UdARiEpI2iAmPoSDcwZSSEuWqXyfsMxz/mLGbdw=
1153-
github.com/lightningnetwork/lnd v0.19.0-beta/go.mod h1:hu6zo1zcznx7nViiFlJY8qGDwwGw5LNLdGJ7ICz5Ysc=
1152+
github.com/lightningnetwork/lnd v0.19.0-beta.rc5.0.20250611041824-9e9524766c8a h1:V+YyjXA86E/dC8pa0mXKjs6yFdgpVvwvmIAmtbwIBnw=
1153+
github.com/lightningnetwork/lnd v0.19.0-beta.rc5.0.20250611041824-9e9524766c8a/go.mod h1:aMQspWfx+sBJdTA5zzvWp3ARnFbx3jtiAXcP6OjmeS8=
11541154
github.com/lightningnetwork/lnd/cert v1.2.2 h1:71YK6hogeJtxSxw2teq3eGeuy4rHGKcFf0d0Uy4qBjI=
11551155
github.com/lightningnetwork/lnd/cert v1.2.2/go.mod h1:jQmFn/Ez4zhDgq2hnYSw8r35bqGVxViXhX6Cd7HXM6U=
11561156
github.com/lightningnetwork/lnd/clock v1.1.1 h1:OfR3/zcJd2RhH0RU+zX/77c0ZiOnIMsDIBjgjWdZgA0=
@@ -1163,12 +1163,12 @@ github.com/lightningnetwork/lnd/kvdb v1.4.16 h1:9BZgWdDfjmHRHLS97cz39bVuBAqMc4/p
11631163
github.com/lightningnetwork/lnd/kvdb v1.4.16/go.mod h1:HW+bvwkxNaopkz3oIgBV6NEnV4jCEZCACFUcNg4xSjM=
11641164
github.com/lightningnetwork/lnd/queue v1.1.1 h1:99ovBlpM9B0FRCGYJo6RSFDlt8/vOkQQZznVb18iNMI=
11651165
github.com/lightningnetwork/lnd/queue v1.1.1/go.mod h1:7A6nC1Qrm32FHuhx/mi1cieAiBZo5O6l8IBIoQxvkz4=
1166-
github.com/lightningnetwork/lnd/sqldb v1.0.9 h1:7OHi+Hui823mB/U9NzCdlZTAGSVdDCbjp33+6d/Q+G0=
1167-
github.com/lightningnetwork/lnd/sqldb v1.0.9/go.mod h1:OG09zL/PHPaBJefp4HsPz2YLUJ+zIQHbpgCtLnOx8I4=
1166+
github.com/lightningnetwork/lnd/sqldb v1.0.10 h1:ZLV7TGwjnKupVfCd+DJ43MAc9BKVSFCnvhpSPGKdN3M=
1167+
github.com/lightningnetwork/lnd/sqldb v1.0.10/go.mod h1:c/vWoQfcxu6FAfHzGajkIQi7CEIeIZFhhH4DYh1BJpc=
11681168
github.com/lightningnetwork/lnd/ticker v1.1.1 h1:J/b6N2hibFtC7JLV77ULQp++QLtCwT6ijJlbdiZFbSM=
11691169
github.com/lightningnetwork/lnd/ticker v1.1.1/go.mod h1:waPTRAAcwtu7Ji3+3k+u/xH5GHovTsCoSVpho0KDvdA=
1170-
github.com/lightningnetwork/lnd/tlv v1.3.1 h1:o7CZg06y+rJZfUMAo0WzBLr0pgBWCzrt0f9gpujYUzk=
1171-
github.com/lightningnetwork/lnd/tlv v1.3.1/go.mod h1:pJuiBj1ecr1WWLOtcZ+2+hu9Ey25aJWFIsjmAoPPnmc=
1170+
github.com/lightningnetwork/lnd/tlv v1.3.2 h1:MO4FCk7F4k5xPMqVZF6Nb/kOpxlwPrUQpYjmyKny5s0=
1171+
github.com/lightningnetwork/lnd/tlv v1.3.2/go.mod h1:pJuiBj1ecr1WWLOtcZ+2+hu9Ey25aJWFIsjmAoPPnmc=
11721172
github.com/lightningnetwork/lnd/tor v1.1.6 h1:WHUumk7WgU6BUFsqHuqszI9P6nfhMeIG+rjJBlVE6OE=
11731173
github.com/lightningnetwork/lnd/tor v1.1.6/go.mod h1:qSRB8llhAK+a6kaTPWOLLXSZc6Hg8ZC0mq1sUQ/8JfI=
11741174
github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796 h1:sjOGyegMIhvgfq5oaue6Td+hxZuf3tDC8lAPrFldqFw=

universe/ignore_records.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77

88
"github.com/btcsuite/btcd/btcec/v2"
99
"github.com/btcsuite/btcd/btcec/v2/schnorr"
10+
"github.com/btcsuite/btcd/wire"
1011
"github.com/lightninglabs/taproot-assets/asset"
1112
"github.com/lightninglabs/taproot-assets/mssmt"
1213
"github.com/lightningnetwork/lnd/tlv"
@@ -204,6 +205,21 @@ func (i *SignedIgnoreTuple) UniverseKey() [32]byte {
204205
return i.IgnoreTuple.Val.Hash()
205206
}
206207

208+
// LeafScriptKey returns the script key for the SignedIgnoreTuple.
209+
func (i *SignedIgnoreTuple) LeafScriptKey() asset.ScriptKey {
210+
scriptKeyBytes := i.IgnoreTuple.Val.ScriptKey
211+
212+
keyPub, _ := btcec.ParsePubKey(scriptKeyBytes.SchnorrSerialized())
213+
scriptKey := asset.NewScriptKey(keyPub)
214+
215+
return scriptKey
216+
}
217+
218+
// LeafOutPoint returns the outpoint for the SignedIgnoreTuple.
219+
func (i *SignedIgnoreTuple) LeafOutPoint() wire.OutPoint {
220+
return i.IgnoreTuple.Val.OutPoint
221+
}
222+
207223
// DecodeSignedIgnoreTuple deserializes a SignedIgnoreTuple from the given blob.
208224
func DecodeSignedIgnoreTuple(blob []byte) (SignedIgnoreTuple, error) {
209225
var s SignedIgnoreTuple

universe/interface.go

Lines changed: 9 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -247,12 +247,20 @@ type Leaf struct {
247247

248248
// Amt is the amount of units associated with the coin.
249249
Amt uint64
250+
251+
// IsBurn is a boolean that indicates whether the leaf represents a burn
252+
// or not.
253+
IsBurn bool
250254
}
251255

252256
// SmtLeafNode returns the SMT leaf node for the given leaf.
253257
func (m *Leaf) SmtLeafNode() *mssmt.LeafNode {
254258
amount := m.Amt
255-
if !m.Asset.IsGenesisAsset() {
259+
260+
// For transfer proofs, we just want to track the number of transfers.
261+
// However, for burns (which aren't genesis asset proofs), we still want
262+
// to track the amount as the final sum value.
263+
if !m.Asset.IsGenesisAsset() && !m.IsBurn {
256264
// We set transfer proof amounts to 1 as the transfer universe
257265
// tracks the total number of transfers.
258266
amount = 1
@@ -742,61 +750,6 @@ type DiffEngine interface {
742750
Close() error
743751
}
744752

745-
// Commitment is an on chain universe commitment. This includes the merkle
746-
// proof for a transaction which anchors the target universe root.
747-
type Commitment struct {
748-
// BlockHeight is the height of the block that the commitment is
749-
// contained within.
750-
BlockHeight uint32
751-
752-
// BlockHeader is the block header that commits to the transaction.
753-
BlockHeader wire.BlockHeader
754-
755-
// MerkleProof is a merkle proof for the above transaction that the
756-
// anchor output was included.
757-
MerkleProof *proof.TxMerkleProof
758-
759-
// UniverseRoot is the full Universe root for this commitment.
760-
UniverseRoot mssmt.Node
761-
}
762-
763-
// CommittedIssuanceProof couples together a Bitcoin level merkle proof
764-
// commitment with an issuance proof. This allows remote callers to verify that
765-
// their responses re actually committed to within the chain.
766-
type CommittedIssuanceProof struct {
767-
// ChainProof is the on chain proof that shows the Universe root has
768-
// been stamped in the chain.
769-
ChainProof *Commitment
770-
771-
// TaprootAssetProof is a proof of new asset issuance.
772-
TaprootAssetProof *Proof
773-
}
774-
775-
// ChainCommitter is used to commit a Universe backend in the chain.
776-
type ChainCommitter interface {
777-
// CommitUniverse takes a Universe and returns a new commitment to that
778-
// Universe in the main chain.
779-
CommitUniverse(universe StorageBackend) (*Commitment, error)
780-
}
781-
782-
// Canonical is an interface that allows a caller to query for the latest
783-
// canonical Universe information related to an asset.
784-
//
785-
// TODO(roasbeef): sync methods too, divide into read/write?
786-
type Canonical interface {
787-
StorageBackend
788-
789-
// Query returns a fully proved response for the target base key.
790-
Query(context.Context, LeafKey) (*CommittedIssuanceProof, error)
791-
792-
// LatestCommitment returns the latest chain commitment.
793-
LatestCommitment() (*Commitment, error)
794-
795-
// UpdateChainCommitment takes in a series of chain commitments and
796-
// updates the commitment on chain.
797-
UpdateChainCommitment(chainCommits ...ChainCommitter) (*Commitment, error)
798-
}
799-
800753
// FederationLog is used to keep track of the set Universe servers that
801754
// comprise our current federation. This'll be used by the AutoSyncer to
802755
// periodically push and sync new proof events against the federation.

universe/supplycommit/README.md

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
# Universe Supply Commitment State Machine
2+
3+
This package implements a state machine responsible for managing the on-chain
4+
commitment to the supply of a specific Taproot Asset (identified by its
5+
`asset.Specifier`, namely the group key).
6+
7+
## Rationale and Purpose
8+
9+
Taproot Assets allow for issuance and transfer off-chain, but maintaining a
10+
verifiable, global view of the *total supply* requires an on-chain commitment
11+
mechanism. This state machine addresses that need.
12+
13+
Its primary purpose is to:
14+
15+
1. **Track Supply Changes:** Receive events representing new asset mints
16+
(`NewMintEvent`), asset burns (`NewBurnEvent`), and ignored outputs
17+
(`NewIgnoreEvent`).
18+
19+
2. **Batch Updates:** Collect these supply-altering events over time.
20+
21+
3. **Commit Periodically:** On a regular trigger (`CommitTickEvent`), create a
22+
new cryptographic commitment (an MS-SMT root) representing the current state
23+
of the asset's supply. This involves separate sub-trees for mints, burns, and
24+
ignores, which are then committed into a single root supply tree.
25+
26+
4. **Anchor On-Chain:** Construct, fund, sign, and broadcast a Bitcoin
27+
transaction that anchors this new supply root commitment into the
28+
blockchain. This transaction spends the previous commitment output (if one
29+
exists) and any relevant pre-commitment outputs (from minting transactions).
30+
31+
5. **Finalize State:** Wait for the commitment transaction to confirm on-chain
32+
and then finalize the state update, making the new commitment the canonical
33+
one for the asset.
34+
35+
This ensures that there is a publicly verifiable, tamper-proof record reflecting
36+
the known supply changes for an asset within the Universe.
37+
38+
## Scope
39+
40+
The state machine handles the lifecycle of a single supply commitment update
41+
cycle for a *specific asset specifier*. It manages:
42+
43+
* Receiving and staging supply update events.
44+
* Calculating the new supply root based on staged updates and previous state.
45+
* Interacting with the `Wallet` interface to:
46+
* Derive keys for commitment outputs.
47+
* Fund the commitment transaction.
48+
* Sign the commitment transaction.
49+
* Interacting with the `ChainBridge` to broadcast the transaction and monitor
50+
for confirmation.
51+
52+
* Persisting its state and pending updates via the `StateMachineStore` to
53+
ensure resilience across restarts.
54+
55+
It does *not* handle:
56+
57+
* Discovering supply update events (this is done by other parts of the system
58+
feeding events into the state machine).
59+
60+
* Serving supply proofs to external requesters (this is handled by the broader
61+
Universe server components).
62+
63+
* Managing commitments for multiple different assets simultaneously (each
64+
asset group typically gets its own state machine instance).
65+
66+
67+
## State Machine Overview
68+
69+
The state machine transitions through several states to process supply updates
70+
and create a new on-chain commitment. It starts in an idle `DefaultState`. When
71+
new supply updates arrive, it moves to `UpdatesPendingState`. A periodic
72+
`CommitTickEvent` triggers the commitment process, moving through states for
73+
tree creation (`CommitTreeCreateState`), transaction creation
74+
(`CommitTxCreateState`), signing (`CommitTxSignState`), broadcasting
75+
(`CommitBroadcastState`), and finally finalization (`CommitFinalizeState`) upon
76+
confirmation, before returning to the `DefaultState`.
77+
78+
### States and Transitions
79+
80+
```mermaid
81+
stateDiagram-v2
82+
[*] --> DefaultState: Initialize / Finalize
83+
84+
DefaultState --> UpdatesPendingState: SupplyUpdateEvent
85+
DefaultState --> DefaultState: CommitTickEvent
86+
87+
UpdatesPendingState --> UpdatesPendingState: SupplyUpdateEvent
88+
UpdatesPendingState --> CommitTreeCreateState: CommitTickEvent (emits CreateTreeEvent)
89+
90+
CommitTreeCreateState --> CommitTxCreateState: CreateTreeEvent (emits CreateTxEvent)
91+
CommitTreeCreateState --> CommitTreeCreateState: CommitTickEvent
92+
93+
CommitTxCreateState --> CommitTxSignState: CreateTxEvent (emits SignTxEvent)
94+
95+
CommitTxSignState --> CommitBroadcastState: SignTxEvent (emits BroadcastEvent)
96+
97+
CommitBroadcastState --> CommitBroadcastState: BroadcastEvent (Broadcasts Tx, Registers Conf)
98+
CommitBroadcastState --> CommitFinalizeState: ConfEvent (emits FinalizeEvent)
99+
100+
CommitFinalizeState --> DefaultState: FinalizeEvent (Applies Transition)
101+
```
102+
103+
* **DefaultState:** The idle state. Awaiting new supply updates.
104+
105+
* **UpdatesPendingState:** One or more supply updates have been received and
106+
are staged, waiting for the next commit trigger.
107+
108+
* **CommitTreeCreateState:** Triggered by `CommitTickEvent`. Fetches existing
109+
sub-trees, applies pending updates, calculates the new sub-tree roots, and
110+
calculates the new root supply tree.
111+
112+
* **CommitTxCreateState:** Triggered by `CreateTreeEvent`. Fetches the
113+
previous commitment (if any) and unspent pre-commitments. Constructs the new
114+
commitment transaction (PSBT) spending these inputs and creating the new
115+
commitment output. Funds the PSBT using the wallet.
116+
117+
* **CommitTxSignState:** Triggered by `CreateTxEvent`. Signs the funded
118+
commitment PSBT using the wallet. Persists the signed transaction details and
119+
state before broadcasting.
120+
121+
* **CommitBroadcastState:** Triggered by `SignTxEvent`. Broadcasts the signed
122+
transaction and registers for its confirmation. Waits for the `ConfEvent`.
123+
124+
* **CommitFinalizeState:** Triggered by `ConfEvent`. The commitment
125+
transaction is confirmed. Finalizes the state transition by updating the
126+
canonical supply trees and commitment details in persistent storage.
127+
Transitions back to `DefaultState`.
128+
129+
## Environment and Persistence
130+
131+
The state machine operates within an `Environment` that provides necessary
132+
dependencies like the `Wallet`, `ChainBridge`, `CommitmentTracker`,
133+
`SupplyTreeView`, and `StateMachineStore`. The `StateMachineStore` is crucial
134+
for persisting the current state and any pending updates or intermediate
135+
transaction data, allowing the machine to resume correctly after restarts.

0 commit comments

Comments
 (0)