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

lightningnetwork / lnd / 12312390362

13 Dec 2024 08:44AM UTC coverage: 57.458% (+8.5%) from 48.92%
12312390362

Pull #9343

github

ellemouton
fn: rework the ContextGuard and add tests

In this commit, the ContextGuard struct is re-worked such that the
context that its new main WithCtx method provides is cancelled in sync
with a parent context being cancelled or with it's quit channel being
cancelled. Tests are added to assert the behaviour. In order for the
close of the quit channel to be consistent with the cancelling of the
derived context, the quit channel _must_ be contained internal to the
ContextGuard so that callers are only able to close the channel via the
exposed Quit method which will then take care to first cancel any
derived context that depend on the quit channel before returning.
Pull Request #9343: fn: expand the ContextGuard and add tests

101853 of 177264 relevant lines covered (57.46%)

24972.93 hits per line

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

0.0
/autopilot/combinedattach.go
1
package autopilot
2

3
import (
4
        "fmt"
5

6
        "github.com/btcsuite/btcd/btcutil"
7
)
8

9
// WeightedHeuristic is a tuple that associates a weight to an
10
// AttachmentHeuristic. This is used to determining a node's final score when
11
// querying several heuristics for scores.
12
type WeightedHeuristic struct {
13
        // Weight is this AttachmentHeuristic's relative weight factor. It
14
        // should be between 0.0 and 1.0.
15
        Weight float64
16

17
        AttachmentHeuristic
18
}
19

20
// WeightedCombAttachment is an implementation of the AttachmentHeuristic
21
// interface that combines the scores given by several sub-heuristics into one.
22
type WeightedCombAttachment struct {
23
        heuristics []*WeightedHeuristic
24
}
25

26
// NewWeightedCombAttachment creates a new instance of a WeightedCombAttachment.
27
func NewWeightedCombAttachment(h ...*WeightedHeuristic) (
28
        *WeightedCombAttachment, error) {
×
29

×
30
        // The sum of weights given to the sub-heuristics must sum to exactly
×
31
        // 1.0.
×
32
        var sum float64
×
33
        for _, w := range h {
×
34
                sum += w.Weight
×
35
        }
×
36

37
        if sum != 1.0 {
×
38
                return nil, fmt.Errorf("weights MUST sum to 1.0 (was %v)", sum)
×
39
        }
×
40

41
        return &WeightedCombAttachment{
×
42
                heuristics: h,
×
43
        }, nil
×
44
}
45

46
// A compile time assertion to ensure WeightedCombAttachment meets the
47
// AttachmentHeuristic and ScoreSettable interfaces.
48
var _ AttachmentHeuristic = (*WeightedCombAttachment)(nil)
49
var _ ScoreSettable = (*WeightedCombAttachment)(nil)
50

51
// Name returns the name of this heuristic.
52
//
53
// NOTE: This is a part of the AttachmentHeuristic interface.
54
func (c *WeightedCombAttachment) Name() string {
×
55
        return "weightedcomb"
×
56
}
×
57

58
// NodeScores is a method that given the current channel graph, current set of
59
// local channels and funds available, scores the given nodes according to the
60
// preference of opening a channel with them. The returned channel candidates
61
// maps the NodeID to an attachment directive containing a score and a channel
62
// size.
63
//
64
// The scores is determined by querying the set of sub-heuristics, then
65
// combining these scores into a final score according to the active
66
// configuration.
67
//
68
// The returned scores will be in the range [0, 1.0], where 0 indicates no
69
// improvement in connectivity if a channel is opened to this node, while 1.0
70
// is the maximum possible improvement in connectivity.
71
//
72
// NOTE: This is a part of the AttachmentHeuristic interface.
73
func (c *WeightedCombAttachment) NodeScores(g ChannelGraph, chans []LocalChannel,
74
        chanSize btcutil.Amount, nodes map[NodeID]struct{}) (
75
        map[NodeID]*NodeScore, error) {
×
76

×
77
        // We now query each heuristic to determine the score they give to the
×
78
        // nodes for the given channel size.
×
79
        var subScores []map[NodeID]*NodeScore
×
80
        for _, h := range c.heuristics {
×
81
                log.Tracef("Getting scores from sub heuristic %v", h.Name())
×
82

×
83
                s, err := h.NodeScores(
×
84
                        g, chans, chanSize, nodes,
×
85
                )
×
86
                if err != nil {
×
87
                        return nil, fmt.Errorf("unable to get sub score: %w",
×
88
                                err)
×
89
                }
×
90

91
                subScores = append(subScores, s)
×
92
        }
93

94
        // We combine the scores given by the sub-heuristics by using the
95
        // heuristics' given weight factor.
96
        scores := make(map[NodeID]*NodeScore)
×
97
        for nID := range nodes {
×
98
                score := &NodeScore{
×
99
                        NodeID: nID,
×
100
                }
×
101

×
102
                // Each sub-heuristic should have scored the node, if not it is
×
103
                // implicitly given a zero score by that heuristic.
×
104
                for i, h := range c.heuristics {
×
105
                        sub, ok := subScores[i][nID]
×
106
                        if !ok {
×
107
                                log.Tracef("No score given to node %x by sub "+
×
108
                                        "heuristic %v", nID[:], h.Name())
×
109
                                continue
×
110
                        }
111
                        // Use the heuristic's weight factor to determine of
112
                        // how much weight we should give to this particular
113
                        // score.
114
                        subScore := h.Weight * sub.Score
×
115
                        log.Tracef("Giving node %x a sub score of %v "+
×
116
                                "(%v * %v) from sub heuristic %v", nID[:],
×
117
                                subScore, h.Weight, sub.Score, h.Name())
×
118

×
119
                        score.Score += subScore
×
120
                }
121

122
                log.Tracef("Node %x got final combined score %v", nID[:],
×
123
                        score.Score)
×
124

×
125
                switch {
×
126
                // Instead of adding a node with score 0 to the returned set,
127
                // we just skip it.
128
                case score.Score == 0:
×
129
                        continue
×
130

131
                // Sanity check the new score.
132
                case score.Score < 0 || score.Score > 1.0:
×
133
                        return nil, fmt.Errorf("invalid node score from "+
×
134
                                "combination: %v", score.Score)
×
135
                }
136

137
                scores[nID] = score
×
138
        }
139

140
        return scores, nil
×
141
}
142

143
// SetNodeScores is used to set the internal map from NodeIDs to scores. The
144
// passed scores must be in the range [0, 1.0]. The fist parameter is the name
145
// of the targeted heuristic, to allow recursively target specific
146
// sub-heuristics. The returned boolean indicates whether the targeted
147
// heuristic was found.
148
//
149
// Since this heuristic doesn't keep any internal scores, it will recursively
150
// apply the scores to its sub-heuristics.
151
//
152
// NOTE: This is a part of the ScoreSettable interface.
153
func (c *WeightedCombAttachment) SetNodeScores(targetHeuristic string,
154
        newScores map[NodeID]float64) (bool, error) {
×
155

×
156
        found := false
×
157
        for _, h := range c.heuristics {
×
158
                // It must be ScoreSettable to be available for external
×
159
                // scores.
×
160
                s, ok := h.AttachmentHeuristic.(ScoreSettable)
×
161
                if !ok {
×
162
                        continue
×
163
                }
164

165
                // Heuristic supports scoring, attempt to set them.
166
                applied, err := s.SetNodeScores(targetHeuristic, newScores)
×
167
                if err != nil {
×
168
                        return false, err
×
169
                }
×
170
                found = found || applied
×
171
        }
172

173
        return found, nil
×
174
}
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

© 2025 Coveralls, Inc