/ blockcache / blockcache.go
blockcache.go
1 package blockcache 2 3 import ( 4 "github.com/btcsuite/btcd/btcutil" 5 "github.com/btcsuite/btcd/chaincfg/chainhash" 6 "github.com/btcsuite/btcd/wire" 7 "github.com/lightninglabs/neutrino" 8 "github.com/lightninglabs/neutrino/cache" 9 "github.com/lightninglabs/neutrino/cache/lru" 10 "github.com/lightningnetwork/lnd/lntypes" 11 "github.com/lightningnetwork/lnd/multimutex" 12 ) 13 14 // BlockCache is an lru cache for blocks. 15 type BlockCache struct { 16 Cache *lru.Cache[wire.InvVect, *neutrino.CacheableBlock] 17 HashMutex *multimutex.Mutex[lntypes.Hash] 18 } 19 20 // NewBlockCache creates a new BlockCache with the given maximum capacity. 21 func NewBlockCache(capacity uint64) *BlockCache { 22 return &BlockCache{ 23 Cache: lru.NewCache[wire.InvVect, *neutrino.CacheableBlock]( 24 capacity, 25 ), 26 HashMutex: multimutex.NewMutex[lntypes.Hash](), 27 } 28 } 29 30 // GetBlock first checks to see if the BlockCache already contains the block 31 // with the given hash. If it does then the block is fetched from the cache and 32 // returned. Otherwise the getBlockImpl function is used in order to fetch the 33 // new block and then it is stored in the block cache and returned. 34 func (bc *BlockCache) GetBlock(hash *chainhash.Hash, 35 getBlockImpl func(hash *chainhash.Hash) (*wire.MsgBlock, 36 error)) (*wire.MsgBlock, error) { 37 38 bc.HashMutex.Lock(lntypes.Hash(*hash)) 39 defer bc.HashMutex.Unlock(lntypes.Hash(*hash)) 40 41 // Create an inv vector for getting the block. 42 inv := wire.NewInvVect(wire.InvTypeWitnessBlock, hash) 43 44 // Check if the block corresponding to the given hash is already 45 // stored in the blockCache and return it if it is. 46 cacheBlock, err := bc.Cache.Get(*inv) 47 if err != nil && err != cache.ErrElementNotFound { 48 return nil, err 49 } 50 if cacheBlock != nil { 51 return cacheBlock.MsgBlock(), nil 52 } 53 54 // Fetch the block from the chain backends. 55 msgBlock, err := getBlockImpl(hash) 56 if err != nil { 57 return nil, err 58 } 59 60 // Make a copy of the block so it won't escape to the heap. 61 msgBlockCopy := msgBlock.Copy() 62 block := btcutil.NewBlock(msgBlockCopy) 63 64 // Add the new block to blockCache. If the Cache is at its maximum 65 // capacity then the LFU item will be evicted in favour of this new 66 // block. 67 _, err = bc.Cache.Put( 68 *inv, &neutrino.CacheableBlock{ 69 Block: block, 70 }, 71 ) 72 if err != nil { 73 return nil, err 74 } 75 76 return msgBlockCopy, nil 77 }