• 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

75.0
/watchtower/blob/type.go
1
package blob
2

3
import (
4
        "fmt"
5
        "strings"
6

7
        "github.com/lightningnetwork/lnd/channeldb"
8
)
9

10
// Flag represents a specify option that can be present in a Type.
11
type Flag uint16
12

13
const (
14
        // FlagReward signals that the justice transaction should contain an
15
        // additional output for itself. Signatures sent by the client should
16
        // include the reward script negotiated during session creation. Without
17
        // the flag, there is only one output sweeping clients funds back to
18
        // them solely.
19
        FlagReward Flag = 1
20

21
        // FlagCommitOutputs signals that the blob contains the information
22
        // required to sweep commitment outputs.
23
        FlagCommitOutputs Flag = 1 << 1
24

25
        // FlagAnchorChannel signals that this blob is meant to spend an anchor
26
        // channel, and therefore must expect a P2WSH-style to-remote output if
27
        // one exists.
28
        FlagAnchorChannel Flag = 1 << 2
29

30
        // FlagTaprootChannel signals that this blob is meant to spend a
31
        // taproot channel and therefore must expect P2TR outputs.
32
        FlagTaprootChannel Flag = 1 << 3
33
)
34

35
// Type returns a Type consisting solely of this flag enabled.
UNCOV
36
func (f Flag) Type() Type {
×
UNCOV
37
        return Type(f)
×
UNCOV
38
}
×
39

40
// String returns the name of the flag.
41
func (f Flag) String() string {
3✔
42
        switch f {
3✔
43
        case FlagReward:
3✔
44
                return "FlagReward"
3✔
45
        case FlagCommitOutputs:
3✔
46
                return "FlagCommitOutputs"
3✔
47
        case FlagAnchorChannel:
3✔
48
                return "FlagAnchorChannel"
3✔
49
        case FlagTaprootChannel:
3✔
50
                return "FlagTaprootChannel"
3✔
UNCOV
51
        default:
×
UNCOV
52
                return "FlagUnknown"
×
53
        }
54
}
55

56
// Type is a bit vector composed of Flags that govern various aspects of
57
// reconstructing the justice transaction from an encrypted blob. The flags can
58
// be used to signal behaviors such as which inputs are being swept, which
59
// outputs should be added to the justice transaction, or modify serialization
60
// of the blob itself.
61
type Type uint16
62

63
const (
64
        // TypeAltruistCommit sweeps only commitment outputs to a sweep address
65
        // controlled by the user, and does not give the tower a reward.
66
        TypeAltruistCommit = Type(FlagCommitOutputs)
67

68
        // TypeAltruistAnchorCommit sweeps only commitment outputs from an
69
        // anchor commitment to a sweep address controlled by the user, and does
70
        // not give the tower a reward.
71
        TypeAltruistAnchorCommit = Type(FlagCommitOutputs | FlagAnchorChannel)
72

73
        // TypeRewardCommit sweeps only commitment outputs to a sweep address
74
        // controlled by the user, and pays a negotiated reward to the tower.
75
        TypeRewardCommit = Type(FlagCommitOutputs | FlagReward)
76

77
        // TypeAltruistTaprootCommit sweeps only the commitment outputs from a
78
        // taproot channel commitment to a sweep address controlled by the user,
79
        // and does not give the tower a reward.
80
        TypeAltruistTaprootCommit = Type(FlagCommitOutputs | FlagTaprootChannel)
81
)
82

83
// TypeFromChannel returns the appropriate blob Type for the given channel
84
// type.
85
func TypeFromChannel(chanType channeldb.ChannelType) Type {
3✔
86
        switch {
3✔
87
        case chanType.IsTaproot():
3✔
88
                return TypeAltruistTaprootCommit
3✔
89
        case chanType.HasAnchors():
3✔
90
                return TypeAltruistAnchorCommit
3✔
91
        default:
3✔
92
                return TypeAltruistCommit
3✔
93
        }
94
}
95

96
// Identifier returns a unique, stable string identifier for the blob Type.
97
func (t Type) Identifier() (string, error) {
3✔
98
        switch t {
3✔
99
        case TypeAltruistCommit:
3✔
100
                return "legacy", nil
3✔
101
        case TypeAltruistAnchorCommit:
3✔
102
                return "anchor", nil
3✔
103
        case TypeRewardCommit:
×
104
                return "reward", nil
×
105
        case TypeAltruistTaprootCommit:
3✔
106
                return "taproot", nil
3✔
107
        default:
×
108
                return "", fmt.Errorf("unknown blob type: %v", t)
×
109
        }
110
}
111

112
// CommitmentType returns the appropriate CommitmentType for the given blob Type
113
// and channel type.
114
func (t Type) CommitmentType(chanType *channeldb.ChannelType) (CommitmentType,
115
        error) {
3✔
116

3✔
117
        switch {
3✔
118
        case t.Has(FlagTaprootChannel):
3✔
119
                return TaprootCommitment, nil
3✔
120

121
        case t.Has(FlagAnchorChannel):
3✔
122
                return AnchorCommitment, nil
3✔
123

124
        case t.Has(FlagCommitOutputs):
3✔
125
                if chanType != nil && chanType.IsTweakless() {
6✔
126
                        return LegacyTweaklessCommitment, nil
3✔
127
                }
3✔
128

129
                return LegacyCommitment, nil
3✔
130

UNCOV
131
        default:
×
UNCOV
132
                return 0, ErrUnknownBlobType
×
133
        }
134
}
135

136
// Has returns true if the Type has the passed flag enabled.
137
func (t Type) Has(flag Flag) bool {
3✔
138
        return Flag(t)&flag == flag
3✔
139
}
3✔
140

141
// TypeFromFlags creates a single Type from an arbitrary list of flags.
UNCOV
142
func TypeFromFlags(flags ...Flag) Type {
×
UNCOV
143
        var typ Type
×
UNCOV
144
        for _, flag := range flags {
×
UNCOV
145
                typ |= Type(flag)
×
UNCOV
146
        }
×
147

UNCOV
148
        return typ
×
149
}
150

151
// IsAnchorChannel returns true if the blob type is for an anchor channel.
152
func (t Type) IsAnchorChannel() bool {
3✔
153
        return t.Has(FlagAnchorChannel)
3✔
154
}
3✔
155

156
// IsTaprootChannel returns true if the blob type is for a taproot channel.
157
func (t Type) IsTaprootChannel() bool {
3✔
158
        return t.Has(FlagTaprootChannel)
3✔
159
}
3✔
160

161
// knownFlags maps the supported flags to their name.
162
var knownFlags = map[Flag]struct{}{
163
        FlagReward:         {},
164
        FlagCommitOutputs:  {},
165
        FlagAnchorChannel:  {},
166
        FlagTaprootChannel: {},
167
}
168

169
// String returns a human-readable description of a Type.
170
func (t Type) String() string {
3✔
171
        var (
3✔
172
                hrPieces        []string
3✔
173
                hasUnknownFlags bool
3✔
174
        )
3✔
175

3✔
176
        // Iterate through the possible flags from highest to lowest. This will
3✔
177
        // ensure that the human readable names will be in the same order as the
3✔
178
        // bits (left to right) if the type were to be printed in big-endian
3✔
179
        // byte order.
3✔
180
        for f := Flag(1 << 15); f != 0; f >>= 1 {
6✔
181
                // If this flag is known, we'll add a human-readable name or its
3✔
182
                // inverse depending on whether the type has this flag set.
3✔
183
                if _, ok := knownFlags[f]; ok {
6✔
184
                        if t.Has(f) {
6✔
185
                                hrPieces = append(hrPieces, f.String())
3✔
186
                        } else {
6✔
187
                                hrPieces = append(hrPieces, "No-"+f.String())
3✔
188
                        }
3✔
189
                } else {
3✔
190
                        // Make note of any unknown flags that this type has
3✔
191
                        // set. If any are present, we'll prepend the bit-wise
3✔
192
                        // representation of the type in the final string.
3✔
193
                        if t.Has(f) {
3✔
UNCOV
194
                                hasUnknownFlags = true
×
UNCOV
195
                        }
×
196
                }
197
        }
198

199
        // If there were no unknown flags, we'll simply return the list of human
200
        // readable pieces.
201
        if !hasUnknownFlags {
6✔
202
                return fmt.Sprintf("[%s]", strings.Join(hrPieces, "|"))
3✔
203
        }
3✔
204

205
        // Otherwise, we'll prepend the bit-wise representation to the human
206
        // readable names.
UNCOV
207
        return fmt.Sprintf("%016b[%s]", t, strings.Join(hrPieces, "|"))
×
208
}
209

210
// supportedTypes is the set of all configurations known to be supported by the
211
// package.
212
var supportedTypes = map[Type]struct{}{
213
        TypeAltruistCommit:        {},
214
        TypeRewardCommit:          {},
215
        TypeAltruistAnchorCommit:  {},
216
        TypeAltruistTaprootCommit: {},
217
}
218

219
// IsSupportedType returns true if the given type is supported by the package.
220
func IsSupportedType(blobType Type) bool {
3✔
221
        _, ok := supportedTypes[blobType]
3✔
222
        return ok
3✔
223
}
3✔
224

225
// SupportedTypes returns a list of all supported blob types.
UNCOV
226
func SupportedTypes() []Type {
×
UNCOV
227
        supported := make([]Type, 0, len(supportedTypes))
×
UNCOV
228
        for t := range supportedTypes {
×
UNCOV
229
                supported = append(supported, t)
×
UNCOV
230
        }
×
UNCOV
231
        return supported
×
232
}
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