@@ -137,6 +137,11 @@ type Storage interface {
137
137
// transfer comes in later on.
138
138
InsertScriptKey (ctx context.Context , scriptKey asset.ScriptKey ,
139
139
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 )
140
145
}
141
146
142
147
// KeyRing is used to create script and internal keys for Taproot Asset
@@ -190,6 +195,14 @@ type Book struct {
190
195
// subscriberMtx guards the subscribers map and access to the
191
196
// subscriptionID.
192
197
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
193
206
}
194
207
195
208
// A compile-time assertion to make sure Book satisfies the
@@ -203,6 +216,7 @@ func NewBook(cfg BookConfig) *Book {
203
216
subscribers : make (
204
217
map [uint64 ]* fn.EventReceiver [* AddrWithKeyInfo ],
205
218
),
219
+ decimalDisplayCache : make (map [asset.ID ]fn.Option [uint32 ]),
206
220
}
207
221
}
208
222
@@ -334,6 +348,68 @@ func (b *Book) FetchAssetMetaForAsset(ctx context.Context,
334
348
return meta , nil
335
349
}
336
350
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
+
337
413
// NewAddress creates a new Taproot Asset address based on the input parameters.
338
414
func (b * Book ) NewAddress (ctx context.Context , addrVersion Version ,
339
415
assetID asset.ID , amount uint64 ,
0 commit comments