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

lightningnetwork / lnd / 14193549836

01 Apr 2025 10:40AM UTC coverage: 69.046% (+0.007%) from 69.039%
14193549836

Pull #9665

github

web-flow
Merge e8825f209 into b01f4e514
Pull Request #9665: kvdb: bump etcd libs to v3.5.12

133439 of 193262 relevant lines covered (69.05%)

22119.45 hits per line

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

66.84
/netann/channel_announcement.go
1
package netann
2

3
import (
4
        "bytes"
5
        "errors"
6
        "fmt"
7

8
        "github.com/btcsuite/btcd/btcec/v2"
9
        "github.com/btcsuite/btcd/btcec/v2/schnorr"
10
        "github.com/btcsuite/btcd/btcec/v2/schnorr/musig2"
11
        "github.com/btcsuite/btcd/chaincfg/chainhash"
12
        "github.com/lightningnetwork/lnd/graph/db/models"
13
        "github.com/lightningnetwork/lnd/lnwire"
14
        "github.com/lightningnetwork/lnd/tlv"
15
)
16

17
const (
18
        // chanAnn2MsgName is a string representing the name of the
19
        // ChannelAnnouncement2 message. This string will be used during the
20
        // construction of the tagged hash message to be signed when producing
21
        // the signature for the ChannelAnnouncement2 message.
22
        chanAnn2MsgName = "channel_announcement_2"
23

24
        // chanAnn2SigFieldName is the name of the signature field of the
25
        // ChannelAnnouncement2 message. This string will be used during the
26
        // construction of the tagged hash message to be signed when producing
27
        // the signature for the ChannelAnnouncement2 message.
28
        chanAnn2SigFieldName = "signature"
29
)
30

31
// CreateChanAnnouncement is a helper function which creates all channel
32
// announcements given the necessary channel related database items. This
33
// function is used to transform out database structs into the corresponding wire
34
// structs for announcing new channels to other peers, or simply syncing up a
35
// peer's initial routing table upon connect.
36
func CreateChanAnnouncement(chanProof *models.ChannelAuthProof,
37
        chanInfo *models.ChannelEdgeInfo,
38
        e1, e2 *models.ChannelEdgePolicy) (*lnwire.ChannelAnnouncement1,
39
        *lnwire.ChannelUpdate1, *lnwire.ChannelUpdate1, error) {
15✔
40

15✔
41
        // First, using the parameters of the channel, along with the channel
15✔
42
        // authentication chanProof, we'll create re-create the original
15✔
43
        // authenticated channel announcement.
15✔
44
        chanID := lnwire.NewShortChanIDFromInt(chanInfo.ChannelID)
15✔
45
        chanAnn := &lnwire.ChannelAnnouncement1{
15✔
46
                ShortChannelID:  chanID,
15✔
47
                NodeID1:         chanInfo.NodeKey1Bytes,
15✔
48
                NodeID2:         chanInfo.NodeKey2Bytes,
15✔
49
                ChainHash:       chanInfo.ChainHash,
15✔
50
                BitcoinKey1:     chanInfo.BitcoinKey1Bytes,
15✔
51
                BitcoinKey2:     chanInfo.BitcoinKey2Bytes,
15✔
52
                Features:        lnwire.NewRawFeatureVector(),
15✔
53
                ExtraOpaqueData: chanInfo.ExtraOpaqueData,
15✔
54
        }
15✔
55

15✔
56
        err := chanAnn.Features.Decode(bytes.NewReader(chanInfo.Features))
15✔
57
        if err != nil {
15✔
58
                return nil, nil, nil, err
×
59
        }
×
60
        chanAnn.BitcoinSig1, err = lnwire.NewSigFromECDSARawSignature(
15✔
61
                chanProof.BitcoinSig1Bytes,
15✔
62
        )
15✔
63
        if err != nil {
15✔
64
                return nil, nil, nil, err
×
65
        }
×
66
        chanAnn.BitcoinSig2, err = lnwire.NewSigFromECDSARawSignature(
15✔
67
                chanProof.BitcoinSig2Bytes,
15✔
68
        )
15✔
69
        if err != nil {
15✔
70
                return nil, nil, nil, err
×
71
        }
×
72
        chanAnn.NodeSig1, err = lnwire.NewSigFromECDSARawSignature(
15✔
73
                chanProof.NodeSig1Bytes,
15✔
74
        )
15✔
75
        if err != nil {
15✔
76
                return nil, nil, nil, err
×
77
        }
×
78
        chanAnn.NodeSig2, err = lnwire.NewSigFromECDSARawSignature(
15✔
79
                chanProof.NodeSig2Bytes,
15✔
80
        )
15✔
81
        if err != nil {
15✔
82
                return nil, nil, nil, err
×
83
        }
×
84

85
        // We'll unconditionally queue the channel's existence chanProof as it
86
        // will need to be processed before either of the channel update
87
        // networkMsgs.
88

89
        // Since it's up to a node's policy as to whether they advertise the
90
        // edge in a direction, we don't create an advertisement if the edge is
91
        // nil.
92
        var edge1Ann, edge2Ann *lnwire.ChannelUpdate1
15✔
93
        if e1 != nil {
28✔
94
                edge1Ann, err = ChannelUpdateFromEdge(chanInfo, e1)
13✔
95
                if err != nil {
13✔
96
                        return nil, nil, nil, err
×
97
                }
×
98
        }
99
        if e2 != nil {
27✔
100
                edge2Ann, err = ChannelUpdateFromEdge(chanInfo, e2)
12✔
101
                if err != nil {
12✔
102
                        return nil, nil, nil, err
×
103
                }
×
104
        }
105

106
        return chanAnn, edge1Ann, edge2Ann, nil
15✔
107
}
108

109
// FetchPkScript defines a function that can be used to fetch the output script
110
// for the transaction with the given SCID.
111
type FetchPkScript func(*lnwire.ShortChannelID) ([]byte, error)
112

113
// ValidateChannelAnn validates the channel announcement.
114
func ValidateChannelAnn(a lnwire.ChannelAnnouncement,
115
        fetchPkScript FetchPkScript) error {
232✔
116

232✔
117
        switch ann := a.(type) {
232✔
118
        case *lnwire.ChannelAnnouncement1:
230✔
119
                return validateChannelAnn1(ann)
230✔
120
        case *lnwire.ChannelAnnouncement2:
2✔
121
                return validateChannelAnn2(ann, fetchPkScript)
2✔
122
        default:
×
123
                return fmt.Errorf("unhandled implementation of "+
×
124
                        "lnwire.ChannelAnnouncement: %T", a)
×
125
        }
126
}
127

128
// validateChannelAnn1 validates the channel announcement message and checks
129
// that node signatures covers the announcement message, and that the bitcoin
130
// signatures covers the node keys.
131
func validateChannelAnn1(a *lnwire.ChannelAnnouncement1) error {
230✔
132
        // First, we'll compute the digest (h) which is to be signed by each of
230✔
133
        // the keys included within the node announcement message. This hash
230✔
134
        // digest includes all the keys, so the (up to 4 signatures) will
230✔
135
        // attest to the validity of each of the keys.
230✔
136
        data, err := a.DataToSign()
230✔
137
        if err != nil {
230✔
138
                return err
×
139
        }
×
140
        dataHash := chainhash.DoubleHashB(data)
230✔
141

230✔
142
        // First we'll verify that the passed bitcoin key signature is indeed a
230✔
143
        // signature over the computed hash digest.
230✔
144
        bitcoinSig1, err := a.BitcoinSig1.ToSignature()
230✔
145
        if err != nil {
230✔
146
                return err
×
147
        }
×
148
        bitcoinKey1, err := btcec.ParsePubKey(a.BitcoinKey1[:])
230✔
149
        if err != nil {
230✔
150
                return err
×
151
        }
×
152
        if !bitcoinSig1.Verify(dataHash, bitcoinKey1) {
230✔
153
                return errors.New("can't verify first bitcoin signature")
×
154
        }
×
155

156
        // If that checks out, then we'll verify that the second bitcoin
157
        // signature is a valid signature of the bitcoin public key over hash
158
        // digest as well.
159
        bitcoinSig2, err := a.BitcoinSig2.ToSignature()
230✔
160
        if err != nil {
230✔
161
                return err
×
162
        }
×
163
        bitcoinKey2, err := btcec.ParsePubKey(a.BitcoinKey2[:])
230✔
164
        if err != nil {
230✔
165
                return err
×
166
        }
×
167
        if !bitcoinSig2.Verify(dataHash, bitcoinKey2) {
230✔
168
                return errors.New("can't verify second bitcoin signature")
×
169
        }
×
170

171
        // Both node signatures attached should indeed be a valid signature
172
        // over the selected digest of the channel announcement signature.
173
        nodeSig1, err := a.NodeSig1.ToSignature()
230✔
174
        if err != nil {
230✔
175
                return err
×
176
        }
×
177
        nodeKey1, err := btcec.ParsePubKey(a.NodeID1[:])
230✔
178
        if err != nil {
230✔
179
                return err
×
180
        }
×
181
        if !nodeSig1.Verify(dataHash, nodeKey1) {
230✔
182
                return errors.New("can't verify data in first node signature")
×
183
        }
×
184

185
        nodeSig2, err := a.NodeSig2.ToSignature()
230✔
186
        if err != nil {
230✔
187
                return err
×
188
        }
×
189
        nodeKey2, err := btcec.ParsePubKey(a.NodeID2[:])
230✔
190
        if err != nil {
230✔
191
                return err
×
192
        }
×
193
        if !nodeSig2.Verify(dataHash, nodeKey2) {
230✔
194
                return errors.New("can't verify data in second node signature")
×
195
        }
×
196

197
        return nil
230✔
198
}
199

200
// validateChannelAnn2 validates the channel announcement message and checks
201
// that message signature covers the announcement message.
202
func validateChannelAnn2(a *lnwire.ChannelAnnouncement2,
203
        fetchPkScript FetchPkScript) error {
2✔
204

2✔
205
        dataHash, err := ChanAnn2DigestToSign(a)
2✔
206
        if err != nil {
2✔
207
                return err
×
208
        }
×
209

210
        sig, err := a.Signature.ToSignature()
2✔
211
        if err != nil {
2✔
212
                return err
×
213
        }
×
214

215
        nodeKey1, err := btcec.ParsePubKey(a.NodeID1.Val[:])
2✔
216
        if err != nil {
2✔
217
                return err
×
218
        }
×
219

220
        nodeKey2, err := btcec.ParsePubKey(a.NodeID2.Val[:])
2✔
221
        if err != nil {
2✔
222
                return err
×
223
        }
×
224

225
        keys := []*btcec.PublicKey{
2✔
226
                nodeKey1, nodeKey2,
2✔
227
        }
2✔
228

2✔
229
        // If the bitcoin keys are provided in the announcement, then it is
2✔
230
        // assumed that the signature of the announcement is a 4-of-4 MuSig2
2✔
231
        // over the bitcoin keys and node ID keys.
2✔
232
        if a.BitcoinKey1.IsSome() && a.BitcoinKey2.IsSome() {
3✔
233
                var (
1✔
234
                        btcKey1 tlv.RecordT[tlv.TlvType12, [33]byte]
1✔
235
                        btcKey2 tlv.RecordT[tlv.TlvType14, [33]byte]
1✔
236
                )
1✔
237

1✔
238
                btcKey1 = a.BitcoinKey1.UnwrapOr(btcKey1)
1✔
239
                btcKey2 = a.BitcoinKey2.UnwrapOr(btcKey2)
1✔
240

1✔
241
                bitcoinKey1, err := btcec.ParsePubKey(btcKey1.Val[:])
1✔
242
                if err != nil {
1✔
243
                        return err
×
244
                }
×
245

246
                bitcoinKey2, err := btcec.ParsePubKey(btcKey2.Val[:])
1✔
247
                if err != nil {
1✔
248
                        return err
×
249
                }
×
250

251
                keys = append(keys, bitcoinKey1, bitcoinKey2)
1✔
252
        } else {
1✔
253
                // If bitcoin keys are not provided, then we need to get the
1✔
254
                // on-chain output key since this will be the 3rd key in the
1✔
255
                // 3-of-3 MuSig2 signature.
1✔
256
                pkScript, err := fetchPkScript(&a.ShortChannelID.Val)
1✔
257
                if err != nil {
1✔
258
                        return err
×
259
                }
×
260

261
                outputKey, err := schnorr.ParsePubKey(pkScript[2:])
1✔
262
                if err != nil {
1✔
263
                        return err
×
264
                }
×
265

266
                keys = append(keys, outputKey)
1✔
267
        }
268

269
        aggKey, _, _, err := musig2.AggregateKeys(keys, true)
2✔
270
        if err != nil {
2✔
271
                return err
×
272
        }
×
273

274
        if !sig.Verify(dataHash.CloneBytes(), aggKey.FinalKey) {
2✔
275
                return fmt.Errorf("invalid sig")
×
276
        }
×
277

278
        return nil
2✔
279
}
280

281
// ChanAnn2DigestToSign computes the digest of the message to be signed.
282
func ChanAnn2DigestToSign(a *lnwire.ChannelAnnouncement2) (*chainhash.Hash,
283
        error) {
4✔
284

4✔
285
        data, err := a.DataToSign()
4✔
286
        if err != nil {
4✔
287
                return nil, err
×
288
        }
×
289

290
        return MsgHash(chanAnn2MsgName, chanAnn2SigFieldName, data), nil
4✔
291
}
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