Skip to content

Commit da489a9

Browse files
committed
supplycommit+tapdb: extend FetchSubTrees with block height end param
Add a block height range end parameter to FetchSubTrees, enabling filtering of supply subtree leaves by block height. This allows reconstruction of supply subtrees as they existed at a specific supply commitment block height. This functionality is useful for reproducing a supply commitment at a given block height for syncing purposes.
1 parent 73a24ba commit da489a9

File tree

6 files changed

+126
-11
lines changed

6 files changed

+126
-11
lines changed

rpcserver.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4407,7 +4407,7 @@ func (r *rpcServer) FetchSupplyLeaves(ctx context.Context,
44074407
var subtrees supplycommit.SupplyTrees
44084408
if needsInclusionProofs {
44094409
subtreeResult, err := r.cfg.SupplyCommitManager.FetchSubTrees(
4410-
ctx, assetSpec,
4410+
ctx, assetSpec, fn.None[uint32](),
44114411
)
44124412
if err != nil {
44134413
return nil, fmt.Errorf("failed to fetch subtrees for "+

tapdb/supply_tree.go

Lines changed: 110 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010

1111
"github.com/btcsuite/btcd/btcec/v2"
1212
"github.com/lightninglabs/taproot-assets/asset"
13+
"github.com/lightninglabs/taproot-assets/fn"
1314
"github.com/lightninglabs/taproot-assets/mssmt"
1415
"github.com/lightninglabs/taproot-assets/proof"
1516
"github.com/lightninglabs/taproot-assets/tapdb/sqlc"
@@ -196,10 +197,108 @@ func fetchSubTreeInternal(ctx context.Context, db BaseUniverseStore,
196197
return memTree, nil
197198
}
198199

199-
// FetchSubTrees returns copies of all sub-trees (mint, burn, ignore) for the
200+
// filterSubTree applies filtering to the leaves of a subtree.
201+
func filterSubTree(ctx context.Context,
202+
treeType supplycommit.SupplySubTree, subTree mssmt.Tree,
203+
blockHeightEnd fn.Option[uint32]) (mssmt.Tree, error) {
204+
205+
if blockHeightEnd.IsNone() {
206+
// No filtering needed, return the original tree.
207+
return subTree, nil
208+
}
209+
210+
// Create a new in-memory tree to copy into.
211+
filteredSubTree := mssmt.NewCompactedTree(mssmt.NewDefaultStore())
212+
213+
// Create a predicate function to filter leaves based on block height.
214+
filterPredicate := func(key [32]byte, leaf mssmt.LeafNode) (bool,
215+
error) {
216+
217+
blockHeightEndVal, err := blockHeightEnd.UnwrapOrErr(
218+
fmt.Errorf("block height end not set"),
219+
)
220+
if err != nil {
221+
return false, err
222+
}
223+
224+
// Decode the leaf based on the tree type to extract block
225+
// height.
226+
switch treeType {
227+
case supplycommit.MintTreeType:
228+
// For mint trees, decode mint event to get block
229+
// height.
230+
var mintEvent supplycommit.NewMintEvent
231+
err := mintEvent.Decode(bytes.NewReader(leaf.Value))
232+
if err != nil {
233+
return false, fmt.Errorf("unable to decode "+
234+
"mint event: %w", err)
235+
}
236+
237+
// Extract block height directly from the mint event.
238+
mintBlockHeight := mintEvent.MintHeight
239+
240+
// Include the leaf if it's within range.
241+
return mintBlockHeight <= blockHeightEndVal, nil
242+
243+
case supplycommit.BurnTreeType:
244+
// For burn trees, decode burn leaf to get block height.
245+
var burnLeaf universe.BurnLeaf
246+
err := burnLeaf.Decode(bytes.NewReader(leaf.Value))
247+
if err != nil {
248+
return false, fmt.Errorf("unable to decode "+
249+
"burn leaf: %w", err)
250+
}
251+
252+
// Extract block height directly from the burn proof.
253+
proofBlockHeight := burnLeaf.BurnProof.BlockHeight
254+
255+
// Include the leaf if it's within range.
256+
return proofBlockHeight <= blockHeightEndVal, nil
257+
258+
case supplycommit.IgnoreTreeType:
259+
// For ignore trees, decode signed ignore tuple to get
260+
// block height.
261+
var signedIgnoreTuple universe.SignedIgnoreTuple
262+
err := signedIgnoreTuple.Decode(
263+
bytes.NewReader(leaf.Value),
264+
)
265+
if err != nil {
266+
return false, fmt.Errorf("unable to decode "+
267+
"signed ignore tuple: %w", err)
268+
}
269+
270+
// Extract block height directly from the "ignore"
271+
// tuple.
272+
tupleBlockHeight :=
273+
signedIgnoreTuple.IgnoreTuple.Val.BlockHeight
274+
275+
// Include the leaf if it's within range.
276+
return tupleBlockHeight <= blockHeightEndVal, nil
277+
278+
default:
279+
return false, fmt.Errorf("unknown tree type: %v",
280+
treeType)
281+
}
282+
}
283+
284+
// Copy the persistent tree to the in-memory tree with filtering.
285+
err := subTree.CopyFilter(ctx, filteredSubTree, filterPredicate)
286+
if err != nil {
287+
return nil, fmt.Errorf("unable to copy "+
288+
"sub-tree: %w", err)
289+
}
290+
291+
return filteredSubTree, nil
292+
}
293+
294+
// FetchSubTrees returns copies of all subtrees (mint, burn, ignore) for the
200295
// given asset spec.
296+
//
297+
// If blockHeightEnd is specified, only leaves with a block height less than
298+
// or equal to the given height are included in the returned subtrees.
201299
func (s *SupplyTreeStore) FetchSubTrees(ctx context.Context,
202-
spec asset.Specifier) lfn.Result[supplycommit.SupplyTrees] {
300+
spec asset.Specifier,
301+
blockHeightEnd fn.Option[uint32]) lfn.Result[supplycommit.SupplyTrees] {
203302

204303
groupKey, err := spec.UnwrapGroupKeyOrErr()
205304
if err != nil {
@@ -222,7 +321,15 @@ func (s *SupplyTreeStore) FetchSubTrees(ctx context.Context,
222321
"sub-tree %v: %w", treeType, fetchErr)
223322
}
224323

225-
trees[treeType] = subTree
324+
filteredSubTree, err := filterSubTree(
325+
ctx, treeType, subTree, blockHeightEnd,
326+
)
327+
if err != nil {
328+
return fmt.Errorf("failed to filter "+
329+
"sub-tree %v: %w", treeType, err)
330+
}
331+
332+
trees[treeType] = filteredSubTree
226333
}
227334
return nil
228335
})

universe/supplycommit/env.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -269,9 +269,10 @@ type SupplyTreeView interface {
269269
FetchSubTree(ctx context.Context, assetSpec asset.Specifier,
270270
treeType SupplySubTree) lfn.Result[mssmt.Tree]
271271

272-
// FetchSubTrees returns all the sub trees for the given asset spec.
272+
// FetchSubTrees returns all the subtrees for the given asset spec.
273273
FetchSubTrees(ctx context.Context,
274-
assetSpec asset.Specifier) lfn.Result[SupplyTrees]
274+
assetSpec asset.Specifier,
275+
blockHeightEnd fn.Option[uint32]) lfn.Result[SupplyTrees]
275276

276277
// FetchRootSupplyTree returns the root supply tree which contains a
277278
// commitment to each of the sub trees.

universe/supplycommit/manager.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -531,7 +531,9 @@ func (m *Manager) FetchCommitment(ctx context.Context,
531531
"supply tree: %w", err)
532532
}
533533

534-
subtrees, err := m.cfg.TreeView.FetchSubTrees(ctx, assetSpec).Unpack()
534+
subtrees, err := m.cfg.TreeView.FetchSubTrees(
535+
ctx, assetSpec, fn.None[uint32](),
536+
).Unpack()
535537
if err != nil {
536538
return zero, fmt.Errorf("unable to fetch supply commit sub "+
537539
"trees: %w", err)
@@ -565,11 +567,14 @@ func (m *Manager) FetchSupplyLeavesByHeight(
565567

566568
// FetchSubTrees returns all the sub trees for the given asset specifier.
567569
func (m *Manager) FetchSubTrees(ctx context.Context,
568-
assetSpec asset.Specifier) (SupplyTrees, error) {
570+
assetSpec asset.Specifier,
571+
blockHeightEnd fn.Option[uint32]) (SupplyTrees, error) {
569572

570573
var zero SupplyTrees
571574

572-
subtrees, err := m.cfg.TreeView.FetchSubTrees(ctx, assetSpec).Unpack()
575+
subtrees, err := m.cfg.TreeView.FetchSubTrees(
576+
ctx, assetSpec, blockHeightEnd,
577+
).Unpack()
573578
if err != nil {
574579
return zero, fmt.Errorf("unable to fetch sub trees: %w", err)
575580
}

universe/supplycommit/mock.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/btcsuite/btcd/chaincfg/chainhash"
1212
"github.com/btcsuite/btcd/wire"
1313
"github.com/lightninglabs/taproot-assets/asset"
14+
"github.com/lightninglabs/taproot-assets/fn"
1415
"github.com/lightninglabs/taproot-assets/mssmt"
1516
"github.com/lightninglabs/taproot-assets/proof"
1617
"github.com/lightninglabs/taproot-assets/tapsend"
@@ -36,7 +37,8 @@ func (m *mockSupplyTreeView) FetchSubTree(_ context.Context,
3637
}
3738

3839
func (m *mockSupplyTreeView) FetchSubTrees(_ context.Context,
39-
assetSpec asset.Specifier) lfn.Result[SupplyTrees] {
40+
assetSpec asset.Specifier,
41+
blockHeightEnd fn.Option[uint32]) lfn.Result[SupplyTrees] {
4042

4143
args := m.Called(assetSpec)
4244
return args.Get(0).(lfn.Result[SupplyTrees])

universe/supplycommit/transitions.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ func (c *CommitTreeCreateState) ProcessEvent(event Event,
372372
//
373373
// TODO(roasbeef): sanity check on population of map?
374374
oldSupplyTrees, err := env.TreeView.FetchSubTrees(
375-
ctx, env.AssetSpec,
375+
ctx, env.AssetSpec, fn.None[uint32](),
376376
).Unpack()
377377
if err != nil {
378378
return nil, fmt.Errorf("unable to fetch old sub "+

0 commit comments

Comments
 (0)