Skip to content

Commit d786104

Browse files
committed
tapdb: add supply_tree.md documentation for supply tree
1 parent 89e570b commit d786104

File tree

1 file changed

+146
-0
lines changed

1 file changed

+146
-0
lines changed

tapdb/supply_tree.md

+146
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
# Taproot Asset Supply Tree Persistence
2+
3+
This document describes the database schema and Go implementation (`tapdb/supply_tree.go`) responsible for persistently storing and managing Taproot Asset Supply Trees within the Universe.
4+
5+
## Purpose
6+
7+
The primary goal of the supply tree system is to create a verifiable, on-chain commitment to the total supply changes (mints, burns, ignores) for a specific asset group. While individual asset states are tracked elsewhere, the supply tree provides a consolidated, aggregatable view anchored to the Bitcoin blockchain. This allows anyone to verify the net issuance changes for an asset group over time by inspecting the sequence of on-chain supply root commitments.
8+
9+
## Schema Overview
10+
11+
The persistence layer utilizes two main tables, introduced in migration `000035_supply_tree.up.sql`, in conjunction with the existing `mssmt_roots` and `mssmt_nodes` tables which store the actual Merkle Sum Sparse Tree (MS-SMT) data.
12+
13+
1. **`universe_supply_roots`**:
14+
* Stores the root entry point for the supply tree of a specific asset group.
15+
* `id`: Primary key.
16+
* `namespace_root` (UNIQUE, FK -> `mssmt_roots.namespace`): The unique namespace identifier used in `mssmt_nodes` and `mssmt_roots` for this specific root supply tree. The format is `supply-root-<group_key_hex>`.
17+
* `group_key` (UNIQUE, BLOB): The compressed public key identifying the asset group this supply tree belongs to.
18+
19+
2. **`universe_supply_leaves`**:
20+
* Represents the leaves within a specific root supply tree. Each leaf points to the root of a *sub-tree* (Mint, Burn, or Ignore).
21+
* `id`: Primary key.
22+
* `supply_root_id` (FK -> `universe_supply_roots.id`): References the parent root supply tree.
23+
* `sub_tree_type` (TEXT, FK -> `proof_types.proof_type`): The type of sub-tree this leaf represents ('mint_supply', 'burn', 'ignore').
24+
* `leaf_node_key` (BLOB): The specific key used for this leaf within the *root* supply tree's MS-SMT. This key is derived deterministically from the `sub_tree_type`.
25+
* `leaf_node_namespace` (VARCHAR): The namespace identifier for the *sub-tree* itself within `mssmt_nodes`. The format is `supply-sub-<type>-<group_key_hex>`.
26+
* `UNIQUE(supply_root_id, sub_tree_type)`: Ensures a root tree has only one leaf per sub-tree type.
27+
28+
### Schema Relationships (Mermaid Diagram)
29+
30+
```mermaid
31+
erDiagram
32+
universe_supply_roots ||--o{ universe_supply_leaves : contains
33+
universe_supply_roots }|--|| mssmt_roots : uses_namespace
34+
universe_supply_leaves }|--|| mssmt_nodes : points_to_subtree_root
35+
universe_supply_leaves }|--|| proof_types : has_type
36+
universe_supply_roots ||--o| asset_groups : conceptual_link
37+
38+
universe_supply_roots {
39+
INTEGER id PK
40+
VARCHAR namespace_root UK "FK(mssmt_roots.namespace)"
41+
BLOB group_key UK
42+
}
43+
44+
universe_supply_leaves {
45+
INTEGER id PK
46+
BIGINT supply_root_id FK
47+
TEXT sub_tree_type "FK(proof_types.proof_type)"
48+
BLOB leaf_node_key
49+
VARCHAR leaf_node_namespace "Namespace for sub-tree in mssmt_nodes"
50+
}
51+
52+
mssmt_roots {
53+
VARCHAR namespace PK
54+
BLOB root_hash "FK(mssmt_nodes.hash_key, mssmt_nodes.namespace)"
55+
}
56+
57+
mssmt_nodes {
58+
BLOB hash_key PK
59+
VARCHAR namespace PK
60+
BLOB l_hash_key
61+
BLOB r_hash_key
62+
BLOB key
63+
BLOB value
64+
BIGINT sum
65+
}
66+
67+
proof_types {
68+
TEXT proof_type PK
69+
}
70+
71+
asset_groups {
72+
INTEGER group_id PK
73+
BLOB tweaked_group_key UK
74+
BLOB tapscript_root "NULL"
75+
BIGINT internal_key_id FK "REFERENCES internal_keys(key_id)"
76+
BIGINT genesis_point_id FK "REFERENCES genesis_points(genesis_id)"
77+
INTEGER version
78+
INTEGER custom_subtree_root_id FK "REFERENCES tapscript_roots(root_id) NULL"
79+
}
80+
```
81+
*Note: The link between `universe_supply_leaves` and `mssmt_nodes` is indirect. The `leaf_node_namespace` identifies the sub-tree, and the actual sub-tree root node's hash and sum are stored as the `value` and `sum` of the leaf node identified by `leaf_node_key` within the *root* tree's namespace (`universe_supply_roots.namespace_root`).*
82+
83+
## Tree Structure
84+
85+
The system employs a two-tiered tree structure for each asset group: a single **Root Supply Tree** whose leaves point to three distinct **Sub-Trees** (Mint, Burn, Ignore).
86+
87+
### Root Supply Tree
88+
89+
* **Purpose:** Aggregates the state of all supply changes (mints, burns, ignores) for a single asset group into one verifiable root hash and sum. This root is what gets committed on-chain.
90+
* **Identifier:** `universe_supply_roots.namespace_root` (`supply-root-<group_key_hex>`).
91+
* **Storage:** Managed by `universe_supply_roots` and stored within `mssmt_nodes` under the root namespace.
92+
* **Leaves:**
93+
* There are exactly three potential leaves in the root tree, one for each sub-tree type.
94+
* **Key:** Determined by the sub-tree type using `supplycommit.SupplySubTree.UniverseKey()`. This provides a stable key for each sub-tree type (e.g., `sha256("mint_supply")`, `sha256("burn")`, `sha256("ignore")`).
95+
* **Value:** The `NodeHash()` of the root node of the corresponding sub-tree.
96+
* **Sum:** The `NodeSum()` (total aggregated amount/value) of the root node of the corresponding sub-tree.
97+
* **Linkage:** The `universe_supply_leaves` table links the `supply_root_id`, the `sub_tree_type`, the `leaf_node_key` used in the root tree, and the `leaf_node_namespace` where the sub-tree resides.
98+
99+
### Sub-Trees
100+
101+
Each asset group has three independent sub-trees, each tracking a specific type of supply event. They are stored as separate MS-SMTs within `mssmt_nodes` using distinct namespaces.
102+
103+
* **Identifier:** `universe_supply_leaves.leaf_node_namespace` (`supply-sub-<type>-<group_key_hex>`).
104+
* **Storage:** Stored within `mssmt_nodes` under their respective namespaces. The roots of these trees are referenced by the leaves of the main Root Supply Tree.
105+
106+
1. **Mint Sub-Tree (`supplycommit.MintTreeType`)**
107+
* **Namespace:** `supply-sub-mint_supply-<group_key_hex>`
108+
* **Purpose:** Tracks all successful asset minting events for the group.
109+
* **Leaves:**
110+
* **Key:** `universe.LeafKey` derived from the minting outpoint and the asset's script key.
111+
* **Value:** The serialized issuance `proof.Proof`.
112+
* **Sum:** The amount of the asset minted in that event.
113+
* **Root:** The root hash represents the commitment to all minting proofs, and the root sum represents the total amount minted for the group.
114+
115+
2. **Burn Sub-Tree (`supplycommit.BurnTreeType`)**
116+
* **Namespace:** `supply-sub-burn-<group_key_hex>`
117+
* **Purpose:** Tracks all confirmed asset burn events for the group.
118+
* **Leaves:**
119+
* **Key:** `universe.LeafKey` derived from the burn outpoint and the asset's script key.
120+
* **Value:** The serialized burn `proof.Proof`.
121+
* **Sum:** The amount of the asset burned in that event.
122+
* **Root:** The root hash represents the commitment to all burn proofs, and the root sum represents the total amount burned for the group.
123+
124+
3. **Ignore Sub-Tree (`supplycommit.IgnoreTreeType`)**
125+
* **Namespace:** `supply-sub-ignore-<group_key_hex>`
126+
* **Purpose:** Tracks outputs associated with the asset group that are provably unspendable or should otherwise be ignored for supply calculation (e.g., due to script conditions, explicit ignore proofs).
127+
* **Leaves:**
128+
* **Key:** The hash of the `universe.IgnoreTuple` value (`IgnoreTuple.Val.Hash()`).
129+
* **Value:** The serialized `universe.SignedIgnoreTuple`.
130+
* **Sum:** The amount associated with the ignored output.
131+
* **Root:** The root hash represents the commitment to all ignored tuples, and the root sum represents the total amount ignored for the group.
132+
133+
## Implementation (`tapdb/supply_tree.go`)
134+
135+
The `tapdb.SupplyTreeStore` provides the Go interface for interacting with the persisted supply trees.
136+
137+
* **Core Logic:** The `upsertSupplyTreeLeaf` function is central. When a sub-tree (e.g., Mint) is updated, its new root node (hash and sum) is computed. `upsertSupplyTreeLeaf` then takes this new sub-tree root and inserts/updates the corresponding leaf in the *main* Root Supply Tree. It handles creating/updating entries in `universe_supply_roots` and `universe_supply_leaves` as needed.
138+
* **Atomicity:** All updates are performed within database transactions managed by the `BatchedUniverseTree` interface (`ExecTx`), ensuring that updates to sub-trees and the corresponding root tree leaf are atomic.
139+
* **Batching:** `applySupplyUpdatesInternal` processes a batch of `supplycommit.SupplyUpdateEvent`s. It groups them by type, updates the relevant sub-trees (calling helpers like `registerMintSupplyInternal`, `insertBurnsInternal`, `addTuplesInternal`), and then calls `upsertSupplyTreeLeaf` for each modified sub-tree to update the main Root Supply Tree.
140+
* **Initialization:** `initEmptySupplyTrees` sets up the initial database state for a new asset group, creating the root tree entry and the three leaf entries pointing to canonical empty sub-tree roots.
141+
* **Fetching:** Functions like `FetchSubTree`, `FetchSubTrees`, and `FetchRootSupplyTree` allow retrieving copies of the persisted trees for inspection or use elsewhere. They read the data from the database and reconstruct the MS-SMT in memory.
142+
* **Namespacing:** The `rootSupplyNamespace` and `subTreeNamespace` functions generate the unique string identifiers used to partition the different trees within the shared `mssmt_nodes` table.
143+
144+
## Conclusion
145+
146+
The supply tree persistence layer provides a robust and verifiable mechanism for tracking and committing to the supply dynamics of Taproot Asset groups. By leveraging MS-SMTs and a two-tiered structure recorded in dedicated SQL tables, it allows for efficient updates and provides the foundation for on-chain supply commitments managed by the `universe/supplycommit` state machine.

0 commit comments

Comments
 (0)