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

lightningnetwork / lnd / 21485572389

29 Jan 2026 04:09PM UTC coverage: 65.247% (+0.2%) from 65.074%
21485572389

Pull #10089

github

web-flow
Merge 22d34d15e into 19b2ad797
Pull Request #10089: Onion message forwarding

1152 of 1448 new or added lines in 23 files covered. (79.56%)

4109 existing lines in 29 files now uncovered.

139515 of 213825 relevant lines covered (65.25%)

20529.09 hits per line

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

59.68
/onionmessage/resolver.go
1
package onionmessage
2

3
import (
4
        "encoding/hex"
5

6
        "github.com/btcsuite/btcd/btcec/v2"
7
        "github.com/lightninglabs/neutrino/cache/lru"
8
        graphdb "github.com/lightningnetwork/lnd/graph/db"
9
        "github.com/lightningnetwork/lnd/lnwire"
10
)
11

12
const (
13
        // defaultSCIDCacheSize is the default number of SCID to pubkey mappings
14
        // to cache. This is relatively small since onion message forwarding via
15
        // SCID is expected to be infrequent compared to forwarding via explicit
16
        // node ID.
17
        defaultSCIDCacheSize = 1000
18
)
19

20
// cachedPubKey is a wrapper around a compressed public key that implements the
21
// cache.Value interface required by the LRU cache.
22
type cachedPubKey struct {
23
        pubKeyBytes [33]byte
24
}
25

26
// Size returns the "size" of an entry. We return 1 as we just want to limit
27
// the total number of entries rather than do accurate size accounting.
28
func (c *cachedPubKey) Size() (uint64, error) {
2✔
29
        return 1, nil
2✔
30
}
2✔
31

32
// GraphNodeResolver resolves node public keys from short channel IDs using the
33
// channel graph. It maintains an LRU cache to avoid repeated database lookups
34
// for frequently used SCIDs.
35
type GraphNodeResolver struct {
36
        graph  *graphdb.ChannelGraph
37
        ourPub *btcec.PublicKey
38

39
        // scidCache is an LRU cache mapping SCID (as uint64) to the remote
40
        // node's compressed public key bytes.
41
        scidCache *lru.Cache[uint64, *cachedPubKey]
42
}
43

44
// NewGraphNodeResolver creates a new GraphNodeResolver with the given channel
45
// graph and our node's public key. It initializes an LRU cache for SCID
46
// lookups.
47
func NewGraphNodeResolver(graph *graphdb.ChannelGraph,
48
        ourPub *btcec.PublicKey) *GraphNodeResolver {
2✔
49

2✔
50
        return &GraphNodeResolver{
2✔
51
                graph:  graph,
2✔
52
                ourPub: ourPub,
2✔
53
                scidCache: lru.NewCache[uint64, *cachedPubKey](
2✔
54
                        defaultSCIDCacheSize,
2✔
55
                ),
2✔
56
        }
2✔
57
}
2✔
58

59
// RemotePubFromSCID resolves a node public key from a short channel ID.
60
// It first checks the LRU cache and falls back to a database lookup on cache
61
// miss.
62
func (r *GraphNodeResolver) RemotePubFromSCID(
63
        scid lnwire.ShortChannelID) (*btcec.PublicKey, error) {
2✔
64

2✔
65
        scidInt := scid.ToUint64()
2✔
66

2✔
67
        // Check the cache first.
2✔
68
        if cached, err := r.scidCache.Get(scidInt); err == nil {
2✔
NEW
69
                pubKey, parseErr := btcec.ParsePubKey(cached.pubKeyBytes[:])
×
NEW
70
                if parseErr == nil {
×
NEW
71
                        log.Tracef("Resolved SCID %v from cache to node %s",
×
NEW
72
                                scid,
×
NEW
73
                                hex.EncodeToString(cached.pubKeyBytes[:]))
×
NEW
74

×
NEW
75
                        return pubKey, nil
×
NEW
76
                }
×
77

78
                // Cache contained invalid data, fall through to DB lookup.
NEW
79
                log.Debugf("Invalid cached pubkey for SCID %v: %v",
×
NEW
80
                        scid, parseErr)
×
81
        }
82

83
        log.Tracef("Resolving node public key for SCID %v from graph", scid)
2✔
84

2✔
85
        edge, _, _, err := r.graph.FetchChannelEdgesByID(scidInt)
2✔
86
        if err != nil {
2✔
NEW
87
                log.Debugf("Failed to fetch channel edges for SCID %v: %v",
×
NEW
88
                        scid, err)
×
NEW
89

×
NEW
90
                return nil, err
×
NEW
91
        }
×
92

93
        otherNodeKeyBytes, err := edge.OtherNodeKeyBytes(
2✔
94
                r.ourPub.SerializeCompressed(),
2✔
95
        )
2✔
96
        if err != nil {
2✔
NEW
97
                log.Debugf("Failed to get other node key for SCID %v: %v",
×
NEW
98
                        scid, err)
×
NEW
99

×
NEW
100
                return nil, err
×
NEW
101
        }
×
102

103
        pubKey, err := btcec.ParsePubKey(otherNodeKeyBytes[:])
2✔
104
        if err != nil {
2✔
NEW
105
                log.Debugf("Failed to parse public key for SCID %v: %v",
×
NEW
106
                        scid, err)
×
NEW
107

×
NEW
108
                return nil, err
×
NEW
109
        }
×
110

111
        // Cache the result for future lookups. We ignore the return values as
112
        // caching is best-effort and a failure just means the next lookup will
113
        // hit the database again.
114
        _, _ = r.scidCache.Put(scidInt, &cachedPubKey{
2✔
115
                pubKeyBytes: otherNodeKeyBytes,
2✔
116
        })
2✔
117

2✔
118
        log.Tracef("Resolved SCID %v to node %s", scid,
2✔
119
                hex.EncodeToString(pubKey.SerializeCompressed()))
2✔
120

2✔
121
        return pubKey, nil
2✔
122
}
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