@@ -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.
201299func (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 })
0 commit comments