@@ -2,14 +2,12 @@ package tapdb
22
33import (
44 "bytes"
5- "crypto/sha256"
65 "slices"
76 "sort"
87 "sync"
98 "sync/atomic"
109
1110 "github.com/lightninglabs/neutrino/cache/lru"
12- "github.com/lightninglabs/taproot-assets/fn"
1311 "github.com/lightninglabs/taproot-assets/universe"
1412 "github.com/lightningnetwork/lnd/lnutils"
1513)
@@ -67,80 +65,86 @@ func DefaultMultiverseCacheConfig() MultiverseCacheConfig {
6765 }
6866}
6967
70- // ProofKey is used to uniquely identify a proof within a universe. This is
71- // used for the LRU cache for the proofs themselves, which are considered to be
72- // immutable.
73- type ProofKey [32 ]byte
74-
75- // NewProofKey takes a universe identifier and leaf key, and returns a proof
76- // key.
77- func NewProofKey (id universe.Identifier , key universe.LeafKey ) ProofKey {
78- idBytes := id .Bytes ()
79- leafKeyBytes := key .UniverseKey ()
80-
81- // The proof key maps down the ID and the leaf key into a single
82- // 32-byte value: sha256(id || leaf_key)..
83- h := sha256 .New ()
84- h .Write (idBytes [:])
85- h .Write (leafKeyBytes [:])
86-
87- return fn.ToArray [ProofKey ](h .Sum (nil ))
88- }
89-
9068// cachedProofs is a list of cached proof leaves.
9169type cachedProofs []* universe.Proof
9270
93- // Size just returns 1 as we're limiting based on the total number of different
94- // leaf keys we query by. So we might store more than one proof per cache entry
95- // if the universe key's script key isn't set. But we only want a certain number
96- // of different keys stored in the cache.
71+ // Size returns the total byte size of all cached proofs.
9772func (c * cachedProofs ) Size () (uint64 , error ) {
98- return 1 , nil
73+ if c == nil {
74+ return 0 , nil
75+ }
76+
77+ totalBytes := uint64 (0 )
78+ for _ , proof := range * c {
79+ if proof == nil {
80+ continue
81+ }
82+
83+ totalBytes += proof .LowerBoundByteSize ()
84+ }
85+
86+ return totalBytes , nil
9987}
10088
10189// newProofCache creates a new leaf proof cache.
102- func newProofCache (proofCacheSize uint64 ) * lru.Cache [ProofKey , * cachedProofs ] {
103- return lru.NewCache [ProofKey , * cachedProofs ](proofCacheSize )
90+ //
91+ // nolint: lll
92+ func newProofCache (totalCacheBytesSize uint64 ) * lru.Cache [UniverseProofKey , * cachedProofs ] {
93+ return lru.NewCache [UniverseProofKey , * cachedProofs ](
94+ totalCacheBytesSize ,
95+ )
10496}
10597
10698// universeIDKey is a cache key used to uniquely identify a universe within a
10799// multiverse tree cache.
108100type universeIDKey = string
109101
102+ // UniverseProofKey houses the components of a universe proof key. All fields
103+ // must be comparable.
104+ type UniverseProofKey struct {
105+ // uniIDKey is the universe ID key to which the proof belongs.
106+ uniIDKey universe.IdentifierKey
107+
108+ // leafKey is the leaf key of the proof.
109+ leafKeyBytes [32 ]byte
110+ }
111+
112+ // NewUniverseProofKey creates a new universe proof key.
113+ func NewUniverseProofKey (uniID universe.Identifier ,
114+ leafKey universe.LeafKey ) UniverseProofKey {
115+
116+ return UniverseProofKey {
117+ uniIDKey : uniID .Key (),
118+ leafKeyBytes : leafKey .UniverseKey (),
119+ }
120+ }
121+
110122// universeProofCache a map of proof caches for each proof type.
111123type universeProofCache struct {
112- proofsPerUniverse uint64
124+ // maxCacheByteSize is the maximum size of the cache in bytes.
125+ maxCacheByteSize uint64
113126
114- lnutils.SyncMap [universeIDKey , * lru.Cache [ProofKey , * cachedProofs ]]
127+ // cache is the LRU cache for the proofs themselves.
128+ cache * lru.Cache [UniverseProofKey , * cachedProofs ]
115129
116130 * cacheLogger
117131}
118132
119133// newUniverseProofCache creates a new proof cache.
120- func newUniverseProofCache (proofsPerUniverse uint64 ) * universeProofCache {
134+ func newUniverseProofCache (maxCacheByteSize uint64 ) * universeProofCache {
121135 return & universeProofCache {
122- proofsPerUniverse : proofsPerUniverse ,
123- SyncMap : lnutils.SyncMap [
124- universeIDKey , * lru.Cache [ProofKey , * cachedProofs ],
125- ]{},
126- cacheLogger : newCacheLogger ("universe_proofs" ),
136+ maxCacheByteSize : maxCacheByteSize ,
137+ cache : newProofCache (maxCacheByteSize ),
138+ cacheLogger : newCacheLogger ("universe_proofs" ),
127139 }
128140}
129141
130142// fetchProof reads the cached proof for the given ID and leaf key.
131143func (p * universeProofCache ) fetchProof (id universe.Identifier ,
132144 leafKey universe.LeafKey ) []* universe.Proof {
133145
134- // First, get the sub-cache for this universe ID from the map of
135- // caches.
136- assetProofCache , _ := p .LoadOrStore (
137- id .String (), newProofCache (p .proofsPerUniverse ),
138- )
139-
140- // With that lower level cache obtained, we can check to see if we have
141- // a hit or not.
142- proofKey := NewProofKey (id , leafKey )
143- proofFromCache , err := assetProofCache .Get (proofKey )
146+ uniProofKey := NewUniverseProofKey (id , leafKey )
147+ proofFromCache , err := p .cache .Get (uniProofKey )
144148 if err == nil {
145149 p .Hit ()
146150 return * proofFromCache
@@ -155,28 +159,52 @@ func (p *universeProofCache) fetchProof(id universe.Identifier,
155159func (p * universeProofCache ) insertProofs (id universe.Identifier ,
156160 leafKey universe.LeafKey , proofs []* universe.Proof ) {
157161
158- assetProofCache , _ := p .LoadOrStore (
159- id .String (), newProofCache (p .proofsPerUniverse ),
160- )
161-
162- proofKey := NewProofKey (id , leafKey )
162+ uniProofKey := NewUniverseProofKey (id , leafKey )
163163
164164 log .Debugf ("Storing proof(s) in cache (universe_id=%v, leaf_key=%v, " +
165- "proof_key=%x, count=%d)" , id .StringForLog (), leafKey ,
166- proofKey [:], len (proofs ))
165+ "count=%d)" , id .StringForLog (), leafKey , len (proofs ))
167166
168167 proofVal := cachedProofs (proofs )
169- if _ , err := assetProofCache . Put (proofKey , & proofVal ); err != nil {
168+ if _ , err := p . cache . Put (uniProofKey , & proofVal ); err != nil {
170169 log .Errorf ("Unable to insert proof into universe proof " +
171170 "cache: %v" , err )
172171 }
173172}
174173
175- // delProofsForAsset deletes all the proofs for the given asset.
176- func (p * universeProofCache ) delProofsForAsset (id universe.Identifier ) {
177- log .Debugf ("Wiping universe proof cache (universe_id=%v)" , id )
174+ // RemoveUniverseProofs deletes all the proofs for the given universe ID.
175+ func (p * universeProofCache ) RemoveUniverseProofs (id universe.Identifier ) {
176+ log .Debugf ("Removing universe proofs (universe_id=%s)" ,
177+ id .StringForLog ())
178178
179- p .Delete (id .String ())
179+ targetIDKey := id .Key ()
180+ p .cache .Range (
181+ func (key UniverseProofKey , proofs * cachedProofs ) bool {
182+ if key .uniIDKey == targetIDKey {
183+ p .cache .Delete (key )
184+ }
185+ return true
186+ },
187+ )
188+ }
189+
190+ // RemoveLeafKeyProofs deletes all the proofs for the given universe ID and leaf
191+ // key.
192+ func (p * universeProofCache ) RemoveLeafKeyProofs (id universe.Identifier ,
193+ leafKey universe.LeafKey ) {
194+
195+ log .Debugf ("Removing leaf key proofs (universe_id=%s, leaf_key=%v)" ,
196+ id .StringForLog (), leafKey )
197+
198+ targetCacheKey := NewUniverseProofKey (id , leafKey )
199+
200+ p .cache .Range (
201+ func (key UniverseProofKey , proofs * cachedProofs ) bool {
202+ if key == targetCacheKey {
203+ p .cache .Delete (key )
204+ }
205+ return true
206+ },
207+ )
180208}
181209
182210// rootPageQueryKey is a cache key that wraps around a query to fetch all the
0 commit comments