@@ -137,6 +137,11 @@ type Storage interface {
137137 // transfer comes in later on.
138138 InsertScriptKey (ctx context.Context , scriptKey asset.ScriptKey ,
139139 keyType asset.ScriptKeyType ) error
140+
141+ // FetchAllAssetMeta attempts to fetch all asset meta known to the
142+ // database.
143+ FetchAllAssetMeta (
144+ ctx context.Context ) (map [asset.ID ]* proof.MetaReveal , error )
140145}
141146
142147// KeyRing is used to create script and internal keys for Taproot Asset
@@ -190,6 +195,14 @@ type Book struct {
190195 // subscriberMtx guards the subscribers map and access to the
191196 // subscriptionID.
192197 subscriberMtx sync.Mutex
198+
199+ // decimalDisplayCache is a cache for the decimal display value of
200+ // assets. This is used to avoid repeated database queries for the same
201+ // asset ID.
202+ decimalDisplayCache map [asset.ID ]fn.Option [uint32 ]
203+
204+ // decDisplayCacheMtx guards the decimalDisplayCache map.
205+ decDisplayCacheMtx sync.Mutex
193206}
194207
195208// A compile-time assertion to make sure Book satisfies the
@@ -203,6 +216,7 @@ func NewBook(cfg BookConfig) *Book {
203216 subscribers : make (
204217 map [uint64 ]* fn.EventReceiver [* AddrWithKeyInfo ],
205218 ),
219+ decimalDisplayCache : make (map [asset.ID ]fn.Option [uint32 ]),
206220 }
207221}
208222
@@ -334,6 +348,68 @@ func (b *Book) FetchAssetMetaForAsset(ctx context.Context,
334348 return meta , nil
335349}
336350
351+ // DecDisplayForAssetID attempts to fetch the meta reveal for a specific asset
352+ // ID and extract the decimal display value from it.
353+ func (b * Book ) DecDisplayForAssetID (ctx context.Context ,
354+ id asset.ID ) (fn.Option [uint32 ], error ) {
355+
356+ b .decDisplayCacheMtx .Lock ()
357+ defer b .decDisplayCacheMtx .Unlock ()
358+
359+ // If we don't have anything in the cache, we'll attempt to load it.
360+ // This will be re-attempted every time if there are no assets in the
361+ // database. But this isn't expected to remain the case for long.
362+ if len (b .decimalDisplayCache ) == 0 {
363+ // If the cache is empty, we'll populate it with all asset
364+ // metas known to the database.
365+ allMeta , err := b .cfg .Store .FetchAllAssetMeta (ctx )
366+ if err != nil {
367+ return fn .None [uint32 ](), fmt .Errorf ("unable to fetch " +
368+ "all asset meta: %v" , err )
369+ }
370+
371+ for assetID , meta := range allMeta {
372+ if meta == nil {
373+ continue
374+ }
375+
376+ displayOpt , err := meta .DecDisplayOption ()
377+ if err != nil {
378+ return fn .None [uint32 ](), fmt .Errorf ("unable " +
379+ "to extract decimal display option " +
380+ "for asset %v: %v" , assetID , err )
381+ }
382+
383+ b .decimalDisplayCache [assetID ] = displayOpt
384+ }
385+ }
386+
387+ // If we have the value in the cache, return it from there.
388+ if displayOpt , ok := b .decimalDisplayCache [id ]; ok {
389+ return displayOpt , nil
390+ }
391+
392+ // If we don't have the value in the cache, it was added after we filled
393+ // the cache, and we'll attempt to fetch the asset meta from the
394+ // database instead.
395+ meta , err := b .FetchAssetMetaForAsset (ctx , id )
396+ if err != nil {
397+ return fn .None [uint32 ](), fmt .Errorf ("unable to fetch asset " +
398+ "meta for asset_id=%v :%v" , id , err )
399+ }
400+
401+ opt , err := meta .DecDisplayOption ()
402+ if err != nil {
403+ return fn .None [uint32 ](), fmt .Errorf ("unable to extract " +
404+ "decimal display option for asset %v: %v" , id , err )
405+ }
406+
407+ // Store the value in the cache for future lookups.
408+ b .decimalDisplayCache [id ] = opt
409+
410+ return opt , nil
411+ }
412+
337413// NewAddress creates a new Taproot Asset address based on the input parameters.
338414func (b * Book ) NewAddress (ctx context.Context , addrVersion Version ,
339415 assetID asset.ID , amount uint64 ,
0 commit comments