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

lightningnetwork / lnd / 13211764208

08 Feb 2025 03:08AM UTC coverage: 49.288% (-9.5%) from 58.815%
13211764208

Pull #9489

github

calvinrzachman
itest: verify switchrpc server enforces send then track

We prevent the rpc server from allowing onion dispatches for
attempt IDs which have already been tracked by rpc clients.

This helps protect the client from leaking a duplicate onion
attempt. NOTE: This is not the only method for solving this
issue! The issue could be addressed via careful client side
programming which accounts for the uncertainty and async
nature of dispatching onions to a remote process via RPC.
This would require some lnd ChannelRouter changes for how
we intend to use these RPCs though.
Pull Request #9489: multi: add BuildOnion, SendOnion, and TrackOnion RPCs

474 of 990 new or added lines in 11 files covered. (47.88%)

27321 existing lines in 435 files now uncovered.

101192 of 205306 relevant lines covered (49.29%)

1.54 hits per line

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

61.43
/build/sub_logger.go
1
package build
2

3
import (
4
        "fmt"
5
        "sort"
6
        "strings"
7
        "sync"
8

9
        "github.com/btcsuite/btclog/v2"
10
)
11

12
// SubLogCreator can be used to create a new logger for a particular subsystem.
13
type SubLogCreator interface {
14
        // Logger returns a new logger for a particular subsystem.
15
        Logger(subsystemTag string) btclog.Logger
16
}
17

18
// SubLoggerManager manages a set of subsystem loggers. Level updates will be
19
// applied to all the loggers managed by the manager.
20
type SubLoggerManager struct {
21
        genLogger SubLogCreator
22

23
        loggers SubLoggers
24
        mu      sync.Mutex
25
}
26

27
// A compile time check to ensure SubLoggerManager implements the
28
// LeveledSubLogger interface.
29
var _ LeveledSubLogger = (*SubLoggerManager)(nil)
30

31
// NewSubLoggerManager constructs a new SubLoggerManager.
32
func NewSubLoggerManager(handlers ...btclog.Handler) *SubLoggerManager {
3✔
33
        return &SubLoggerManager{
3✔
34
                loggers: make(SubLoggers),
3✔
35
                genLogger: newSubLogGenerator(
3✔
36
                        newHandlerSet(btclog.LevelInfo, handlers...),
3✔
37
                ),
3✔
38
        }
3✔
39
}
3✔
40

41
// GenSubLogger creates a new sub-logger and adds it to the set managed by the
42
// SubLoggerManager. A shutdown callback function is provided to be able to shut
43
// down in case of a critical error.
44
func (r *SubLoggerManager) GenSubLogger(subsystem string,
45
        shutdown func()) btclog.Logger {
3✔
46

3✔
47
        // Create a new logger with the given subsystem tag.
3✔
48
        logger := r.genLogger.Logger(subsystem)
3✔
49

3✔
50
        // Wrap the new logger in a Shutdown logger so that the shutdown
3✔
51
        // call back is called if a critical log is ever written via this new
3✔
52
        // logger.
3✔
53
        l := NewShutdownLogger(logger, shutdown)
3✔
54

3✔
55
        r.RegisterSubLogger(subsystem, l)
3✔
56

3✔
57
        return l
3✔
58
}
3✔
59

60
// RegisterSubLogger registers the given logger under the given subsystem name.
61
func (r *SubLoggerManager) RegisterSubLogger(subsystem string,
62
        logger btclog.Logger) {
3✔
63

3✔
64
        // Add the new logger to the set of loggers managed by the manager.
3✔
65
        r.mu.Lock()
3✔
66
        r.loggers[subsystem] = logger
3✔
67
        r.mu.Unlock()
3✔
68
}
3✔
69

70
// SubLoggers returns all currently registered subsystem loggers for this log
71
// writer.
72
//
73
// NOTE: This is part of the LeveledSubLogger interface.
74
func (r *SubLoggerManager) SubLoggers() SubLoggers {
×
75
        r.mu.Lock()
×
76
        defer r.mu.Unlock()
×
77

×
78
        return r.loggers
×
79
}
×
80

81
// SupportedSubsystems returns a sorted string slice of all keys in the
82
// subsystems map, corresponding to the names of the subsystems.
83
//
84
// NOTE: This is part of the LeveledSubLogger interface.
85
func (r *SubLoggerManager) SupportedSubsystems() []string {
3✔
86
        r.mu.Lock()
3✔
87
        defer r.mu.Unlock()
3✔
88

3✔
89
        // Convert the subsystemLoggers map keys to a string slice.
3✔
90
        subsystems := make([]string, 0, len(r.loggers))
3✔
91
        for subsysID := range r.loggers {
6✔
92
                subsystems = append(subsystems, subsysID)
3✔
93
        }
3✔
94

95
        // Sort the subsystems for stable display.
96
        sort.Strings(subsystems)
3✔
97

3✔
98
        return subsystems
3✔
99
}
100

101
// SetLogLevel sets the logging level for provided subsystem. Invalid
102
// subsystems are ignored. Uninitialized subsystems are dynamically created as
103
// needed.
104
//
105
// NOTE: This is part of the LeveledSubLogger interface.
106
func (r *SubLoggerManager) SetLogLevel(subsystemID string, logLevel string) {
×
107
        r.mu.Lock()
×
108
        defer r.mu.Unlock()
×
109

×
110
        r.setLogLevelUnsafe(subsystemID, logLevel)
×
111
}
×
112

113
// setLogLevelUnsafe sets the logging level for provided subsystem. Invalid
114
// subsystems are ignored. Uninitialized subsystems are dynamically created as
115
// needed.
116
//
117
// NOTE: the SubLoggerManager mutex must be held before calling this method.
118
func (r *SubLoggerManager) setLogLevelUnsafe(subsystemID string,
119
        logLevel string) {
3✔
120

3✔
121
        // Ignore invalid subsystems.
3✔
122
        logger, ok := r.loggers[subsystemID]
3✔
123
        if !ok {
3✔
124
                return
×
125
        }
×
126

127
        // Defaults to info if the log level is invalid.
128
        level, _ := btclog.LevelFromString(logLevel)
3✔
129

3✔
130
        logger.SetLevel(level)
3✔
131
}
132

133
// SetLogLevels sets the log level for all subsystem loggers to the passed
134
// level. It also dynamically creates the subsystem loggers as needed, so it
135
// can be used to initialize the logging system.
136
//
137
// NOTE: This is part of the LeveledSubLogger interface.
138
func (r *SubLoggerManager) SetLogLevels(logLevel string) {
3✔
139
        r.mu.Lock()
3✔
140
        defer r.mu.Unlock()
3✔
141

3✔
142
        // Configure all sub-systems with the new logging level. Dynamically
3✔
143
        // create loggers as needed.
3✔
144
        for subsystemID := range r.loggers {
6✔
145
                r.setLogLevelUnsafe(subsystemID, logLevel)
3✔
146
        }
3✔
147
}
148

149
// SubLoggers is a type that holds a map of subsystem loggers keyed by their
150
// subsystem name.
151
type SubLoggers map[string]btclog.Logger
152

153
// LeveledSubLogger provides the ability to retrieve the subsystem loggers of
154
// a logger and set their log levels individually or all at once.
155
type LeveledSubLogger interface {
156
        // SubLoggers returns the map of all registered subsystem loggers.
157
        SubLoggers() SubLoggers
158

159
        // SupportedSubsystems returns a slice of strings containing the names
160
        // of the supported subsystems. Should ideally correspond to the keys
161
        // of the subsystem logger map and be sorted.
162
        SupportedSubsystems() []string
163

164
        // SetLogLevel assigns an individual subsystem logger a new log level.
165
        SetLogLevel(subsystemID string, logLevel string)
166

167
        // SetLogLevels assigns all subsystem loggers the same new log level.
168
        SetLogLevels(logLevel string)
169
}
170

171
// ParseAndSetDebugLevels attempts to parse the specified debug level and set
172
// the levels accordingly on the given logger. An appropriate error is returned
173
// if anything is invalid.
174
func ParseAndSetDebugLevels(level string, logger LeveledSubLogger) error {
3✔
175
        // Split at the delimiter.
3✔
176
        levels := strings.Split(level, ",")
3✔
177
        if len(levels) == 0 {
3✔
178
                return fmt.Errorf("invalid log level: %v", level)
×
179
        }
×
180

181
        // If the first entry has no =, treat is as the log level for all
182
        // subsystems.
183
        globalLevel := levels[0]
3✔
184
        if !strings.Contains(globalLevel, "=") {
6✔
185
                // Validate debug log level.
3✔
186
                if !validLogLevel(globalLevel) {
3✔
UNCOV
187
                        str := "the specified debug level [%v] is invalid"
×
UNCOV
188

×
UNCOV
189
                        return fmt.Errorf(str, globalLevel)
×
UNCOV
190
                }
×
191

192
                // Change the logging level for all subsystems.
193
                logger.SetLogLevels(globalLevel)
3✔
194

3✔
195
                // The rest will target specific subsystems.
3✔
196
                levels = levels[1:]
3✔
197
        }
198

199
        // Go through the subsystem/level pairs while detecting issues and
200
        // update the log levels accordingly.
201
        for _, logLevelPair := range levels {
3✔
UNCOV
202
                if !strings.Contains(logLevelPair, "=") {
×
UNCOV
203
                        str := "the specified debug level contains an " +
×
UNCOV
204
                                "invalid subsystem/level pair [%v]"
×
UNCOV
205

×
UNCOV
206
                        return fmt.Errorf(str, logLevelPair)
×
UNCOV
207
                }
×
208

209
                // Extract the specified subsystem and log level.
UNCOV
210
                fields := strings.Split(logLevelPair, "=")
×
UNCOV
211
                if len(fields) != 2 {
×
212
                        str := "the specified debug level has an invalid " +
×
213
                                "format [%v] -- use format subsystem1=level1," +
×
214
                                "subsystem2=level2"
×
215

×
216
                        return fmt.Errorf(str, logLevelPair)
×
217
                }
×
UNCOV
218
                subsysID, logLevel := fields[0], fields[1]
×
UNCOV
219
                subLoggers := logger.SubLoggers()
×
UNCOV
220

×
UNCOV
221
                // Validate subsystem.
×
UNCOV
222
                if _, exists := subLoggers[subsysID]; !exists {
×
UNCOV
223
                        str := "the specified subsystem [%v] is invalid -- " +
×
UNCOV
224
                                "supported subsystems are %v"
×
UNCOV
225

×
UNCOV
226
                        return fmt.Errorf(
×
UNCOV
227
                                str, subsysID, logger.SupportedSubsystems(),
×
UNCOV
228
                        )
×
UNCOV
229
                }
×
230

231
                // Validate log level.
UNCOV
232
                if !validLogLevel(logLevel) {
×
233
                        str := "the specified debug level [%v] is invalid"
×
234
                        return fmt.Errorf(str, logLevel)
×
235
                }
×
236

UNCOV
237
                logger.SetLogLevel(subsysID, logLevel)
×
238
        }
239

240
        return nil
3✔
241
}
242

243
// validLogLevel returns whether or not logLevel is a valid debug log level.
244
func validLogLevel(logLevel string) bool {
3✔
245
        switch logLevel {
3✔
UNCOV
246
        case "trace":
×
UNCOV
247
                fallthrough
×
248
        case "debug":
3✔
249
                fallthrough
3✔
250
        case "info":
3✔
251
                fallthrough
3✔
252
        case "warn":
3✔
253
                fallthrough
3✔
254
        case "error":
3✔
255
                fallthrough
3✔
256
        case "critical":
3✔
257
                fallthrough
3✔
258
        case "off":
3✔
259
                return true
3✔
260
        }
261

UNCOV
262
        return false
×
263
}
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