• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lightningnetwork / lnd / 13458015710

21 Feb 2025 01:39PM UTC coverage: 58.816% (-0.02%) from 58.831%
13458015710

Pull #9534

github

ellemouton
graph: refactor Builder network message handling

The exposed AddNode, AddEdge and UpdateEdge methods of the Builder are
currently synchronous since even though they pass messages to the
network handler which spins off the handling in a goroutine, the public
methods still wait for a response from the handling before returning.
The only part that is actually done asynchronously is the topology
notifications.

We previously tried to simplify things in [this
commit](https://github.com/lightningnetwork/lnd/pull/9476/commits/d757b3bcf)
but we soon realised that there was a reason for sending the messages to
the central/synchronous network handler first: it was to ensure
consistency for topology clients: ie, the ordering between when there is
a new topology client or if it is cancelled needs to be consistent and
handled synchronously with new network updates. So for example, if a new
update comes in right after a topology client cancels its subscription,
then it should _not_ be notified. Similariy for new subscriptions. So
this commit was reverted soon after.

We can, however, still simplify things as is done in this commit by
noting that _only topology subscriptions and notifications_ need to be
handled separately. The actual network updates do not need to. So that
is what is done here.

This refactor will make moving the topology subscription logic to a new
subsystem later on much easier.
Pull Request #9534: graph: refactor Builder network message handling

35 of 36 new or added lines in 1 file covered. (97.22%)

70 existing lines in 19 files now uncovered.

136302 of 231742 relevant lines covered (58.82%)

19254.91 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.36
/blockcache/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 {
35✔
22
        return &BlockCache{
35✔
23
                Cache: lru.NewCache[wire.InvVect, *neutrino.CacheableBlock](
35✔
24
                        capacity,
35✔
25
                ),
35✔
26
                HashMutex: multimutex.NewMutex[lntypes.Hash](),
35✔
27
        }
35✔
28
}
35✔
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) {
1,468✔
37

1,468✔
38
        bc.HashMutex.Lock(lntypes.Hash(*hash))
1,468✔
39
        defer bc.HashMutex.Unlock(lntypes.Hash(*hash))
1,468✔
40

1,468✔
41
        // Create an inv vector for getting the block.
1,468✔
42
        inv := wire.NewInvVect(wire.InvTypeWitnessBlock, hash)
1,468✔
43

1,468✔
44
        // Check if the block corresponding to the given hash is already
1,468✔
45
        // stored in the blockCache and return it if it is.
1,468✔
46
        cacheBlock, err := bc.Cache.Get(*inv)
1,468✔
47
        if err != nil && err != cache.ErrElementNotFound {
1,468✔
48
                return nil, err
×
49
        }
×
50
        if cacheBlock != nil {
1,668✔
51
                return cacheBlock.MsgBlock(), nil
200✔
52
        }
200✔
53

54
        // Fetch the block from the chain backends.
55
        msgBlock, err := getBlockImpl(hash)
1,270✔
56
        if err != nil {
1,270✔
UNCOV
57
                return nil, err
×
UNCOV
58
        }
×
59

60
        // Make a copy of the block so it won't escape to the heap.
61
        msgBlockCopy := msgBlock.Copy()
1,270✔
62
        block := btcutil.NewBlock(msgBlockCopy)
1,270✔
63

1,270✔
64
        // Add the new block to blockCache. If the Cache is at its maximum
1,270✔
65
        // capacity then the LFU item will be evicted in favour of this new
1,270✔
66
        // block.
1,270✔
67
        _, err = bc.Cache.Put(
1,270✔
68
                *inv, &neutrino.CacheableBlock{
1,270✔
69
                        Block: block,
1,270✔
70
                },
1,270✔
71
        )
1,270✔
72
        if err != nil {
1,270✔
73
                return nil, err
×
74
        }
×
75

76
        return msgBlockCopy, nil
1,270✔
77
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc