Skip to content

Commit 08de01a

Browse files
committed
Merge branch '0-6-1-pull-requests-1650' into 0-6-1-pull-requests
2 parents fa86360 + 49f4891 commit 08de01a

File tree

7 files changed

+196
-23
lines changed

7 files changed

+196
-23
lines changed

address/book.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
338414
func (b *Book) NewAddress(ctx context.Context, addrVersion Version,
339415
assetID asset.ID, amount uint64,

chain_bridge.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ import (
2727

2828
const (
2929
// maxNumBlocksInCache is the maximum number of blocks we'll cache
30-
// timestamps for. With 100k blocks we should only take up approximately
31-
// 800kB of memory (4 bytes for the block height and 4 bytes for the
30+
// timestamps for. With 400k blocks we should only take up approximately
31+
// 3200kB of memory (4 bytes for the block height and 4 bytes for the
3232
// timestamp, not including any map/cache overhead).
33-
maxNumBlocksInCache = 100_000
33+
maxNumBlocksInCache = 400_000
3434
)
3535

3636
// cacheableTimestamp is a wrapper around an uint32 that can be used as a value

rpcserver.go

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1228,7 +1228,9 @@ func (r *rpcServer) MarshalChainAsset(ctx context.Context, a asset.ChainAsset,
12281228
case meta != nil:
12291229
decDisplay, err = meta.DecDisplayOption()
12301230
default:
1231-
decDisplay, err = r.DecDisplayForAssetID(ctx, a.ID())
1231+
decDisplay, err = r.cfg.AddrBook.DecDisplayForAssetID(
1232+
ctx, a.ID(),
1233+
)
12321234
}
12331235
if err != nil {
12341236
return nil, err
@@ -5440,7 +5442,9 @@ func (r *rpcServer) AssetLeaves(ctx context.Context,
54405442
for i, assetLeaf := range assetLeaves {
54415443
assetLeaf := assetLeaf
54425444

5443-
decDisplay, err := r.DecDisplayForAssetID(ctx, assetLeaf.ID())
5445+
decDisplay, err := r.cfg.AddrBook.DecDisplayForAssetID(
5446+
ctx, assetLeaf.ID(),
5447+
)
54445448
if err != nil {
54455449
return nil, err
54465450
}
@@ -5544,7 +5548,9 @@ func (r *rpcServer) marshalUniverseProofLeaf(ctx context.Context,
55445548
return nil, err
55455549
}
55465550

5547-
decDisplay, err := r.DecDisplayForAssetID(ctx, proof.Leaf.ID())
5551+
decDisplay, err := r.cfg.AddrBook.DecDisplayForAssetID(
5552+
ctx, proof.Leaf.ID(),
5553+
)
55485554
if err != nil {
55495555
return nil, err
55505556
}
@@ -6012,7 +6018,7 @@ func (r *rpcServer) marshalUniverseDiff(ctx context.Context,
60126018

60136019
leaves := make([]*unirpc.AssetLeaf, len(diff.NewLeafProofs))
60146020
for i, leaf := range diff.NewLeafProofs {
6015-
decDisplay, err := r.DecDisplayForAssetID(
6021+
decDisplay, err := r.cfg.AddrBook.DecDisplayForAssetID(
60166022
ctx, leaf.ID(),
60176023
)
60186024
if err != nil {
@@ -6507,7 +6513,7 @@ func (r *rpcServer) marshalAssetSyncSnapshot(ctx context.Context,
65076513
AnchorPoint: a.AnchorPoint.String(),
65086514
}
65096515

6510-
decDisplay, err := r.DecDisplayForAssetID(ctx, a.AssetID)
6516+
decDisplay, err := r.cfg.AddrBook.DecDisplayForAssetID(ctx, a.AssetID)
65116517
if err == nil {
65126518
decDisplay.WhenSome(func(u uint32) {
65136519
rpcAsset.DecimalDisplay = u
@@ -8536,20 +8542,6 @@ func encodeVirtualPackets(packets []*tappsbt.VPacket) ([][]byte, error) {
85368542
return rawPackets, nil
85378543
}
85388544

8539-
// DecDisplayForAssetID attempts to fetch the meta reveal for a specific asset
8540-
// ID and extract the decimal display value from it.
8541-
func (r *rpcServer) DecDisplayForAssetID(ctx context.Context,
8542-
id asset.ID) (fn.Option[uint32], error) {
8543-
8544-
meta, err := r.cfg.AddrBook.FetchAssetMetaForAsset(ctx, id)
8545-
if err != nil {
8546-
return fn.None[uint32](), fmt.Errorf("unable to fetch asset "+
8547-
"meta for asset_id=%v :%v", id, err)
8548-
}
8549-
8550-
return meta.DecDisplayOption()
8551-
}
8552-
85538545
// getInboundPolicy returns the policy of the given channel that points towards
85548546
// our node, so it's the policy set by the remote peer.
85558547
func (r *rpcServer) getInboundPolicy(ctx context.Context, chanID uint64,
@@ -8751,7 +8743,7 @@ func (r *rpcServer) DecodeAssetPayReq(ctx context.Context,
87518743

87528744
// The final piece of information we need is the decimal display
87538745
// information for this asset ID.
8754-
decDisplay, err := r.DecDisplayForAssetID(ctx, assetID)
8746+
decDisplay, err := r.cfg.AddrBook.DecDisplayForAssetID(ctx, assetID)
87558747
if err != nil {
87568748
return nil, err
87578749
}

tapdb/addrs.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ type (
8080

8181
// AssetMeta is the metadata record for an asset.
8282
AssetMeta = sqlc.FetchAssetMetaForAssetRow
83+
84+
// AllAssetMetaRow is a type alias for fetching all asset metadata
85+
// records.
86+
AllAssetMetaRow = sqlc.FetchAllAssetMetaRow
8387
)
8488

8589
var (
@@ -180,6 +184,10 @@ type AddrBook interface {
180184
// FetchAssetMetaForAsset fetches the asset meta for a given asset.
181185
FetchAssetMetaForAsset(ctx context.Context,
182186
assetID []byte) (AssetMeta, error)
187+
188+
// FetchAllAssetMeta fetches all asset metadata records from the
189+
// database.
190+
FetchAllAssetMeta(ctx context.Context) ([]AllAssetMetaRow, error)
183191
}
184192

185193
// AddrBookTxOptions defines the set of db txn options the AddrBook
@@ -1164,6 +1172,49 @@ func (t *TapAddressBook) FetchAssetMetaForAsset(ctx context.Context,
11641172
return assetMeta, nil
11651173
}
11661174

1175+
// FetchAllAssetMeta attempts to fetch all asset meta known to the database.
1176+
func (t *TapAddressBook) FetchAllAssetMeta(
1177+
ctx context.Context) (map[asset.ID]*proof.MetaReveal, error) {
1178+
1179+
var assetMetas map[asset.ID]*proof.MetaReveal
1180+
1181+
readOpts := NewAssetStoreReadTx()
1182+
dbErr := t.db.ExecTx(ctx, &readOpts, func(q AddrBook) error {
1183+
dbMetas, err := q.FetchAllAssetMeta(ctx)
1184+
if err != nil {
1185+
return err
1186+
}
1187+
1188+
assetMetas = make(map[asset.ID]*proof.MetaReveal, len(dbMetas))
1189+
for _, dbMeta := range dbMetas {
1190+
// If no record is present, we should get a
1191+
// sql.ErrNoRows error
1192+
// above.
1193+
metaOpt, err := parseAssetMetaReveal(dbMeta.AssetsMetum)
1194+
if err != nil {
1195+
return fmt.Errorf("unable to parse asset "+
1196+
"meta: %w", err)
1197+
}
1198+
1199+
metaOpt.WhenSome(func(meta proof.MetaReveal) {
1200+
var id asset.ID
1201+
copy(id[:], dbMeta.AssetID)
1202+
assetMetas[id] = &meta
1203+
})
1204+
}
1205+
1206+
return nil
1207+
})
1208+
switch {
1209+
case errors.Is(dbErr, sql.ErrNoRows):
1210+
return nil, address.ErrAssetMetaNotFound
1211+
case dbErr != nil:
1212+
return nil, dbErr
1213+
}
1214+
1215+
return assetMetas, nil
1216+
}
1217+
11671218
// insertFullAssetGen inserts a new asset genesis and optional asset group
11681219
// into the database. A placeholder for the asset meta inserted as well.
11691220
func insertFullAssetGen(ctx context.Context,

tapdb/sqlc/assets.sql.go

Lines changed: 46 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tapdb/sqlc/querier.go

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tapdb/sqlc/queries/assets.sql

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,6 +1034,13 @@ JOIN assets_meta
10341034
ON assets.meta_data_id = assets_meta.meta_id
10351035
WHERE assets.asset_id = $1;
10361036

1037+
-- name: FetchAllAssetMeta :many
1038+
SELECT sqlc.embed(assets_meta), genesis_assets.asset_id
1039+
FROM assets_meta
1040+
JOIN genesis_assets
1041+
ON genesis_assets.meta_data_id = assets_meta.meta_id
1042+
ORDER BY assets_meta.meta_id;
1043+
10371044
-- Upsert a record into the mint_anchor_uni_commitments table.
10381045
-- If a record with the same batch_id and group_key already exists, update the
10391046
-- existing record. Otherwise, insert a new record.

0 commit comments

Comments
 (0)