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

lightningnetwork / lnd / 13408822928

19 Feb 2025 08:59AM UTC coverage: 41.123% (-17.7%) from 58.794%
13408822928

Pull #9521

github

web-flow
Merge d2f397b3c into 0e8786348
Pull Request #9521: unit: remove GOACC, use Go 1.20 native coverage functionality

92496 of 224923 relevant lines covered (41.12%)

18825.83 hits per line

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

47.45
/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) {
1✔
40

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

1✔
56
        err := chanAnn.Features.Decode(bytes.NewReader(chanInfo.Features))
1✔
57
        if err != nil {
1✔
58
                return nil, nil, nil, err
×
59
        }
×
60
        chanAnn.BitcoinSig1, err = lnwire.NewSigFromECDSARawSignature(
1✔
61
                chanProof.BitcoinSig1Bytes,
1✔
62
        )
1✔
63
        if err != nil {
1✔
64
                return nil, nil, nil, err
×
65
        }
×
66
        chanAnn.BitcoinSig2, err = lnwire.NewSigFromECDSARawSignature(
1✔
67
                chanProof.BitcoinSig2Bytes,
1✔
68
        )
1✔
69
        if err != nil {
1✔
70
                return nil, nil, nil, err
×
71
        }
×
72
        chanAnn.NodeSig1, err = lnwire.NewSigFromECDSARawSignature(
1✔
73
                chanProof.NodeSig1Bytes,
1✔
74
        )
1✔
75
        if err != nil {
1✔
76
                return nil, nil, nil, err
×
77
        }
×
78
        chanAnn.NodeSig2, err = lnwire.NewSigFromECDSARawSignature(
1✔
79
                chanProof.NodeSig2Bytes,
1✔
80
        )
1✔
81
        if err != nil {
1✔
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
1✔
93
        if e1 != nil {
1✔
94
                edge1Ann, err = ChannelUpdateFromEdge(chanInfo, e1)
×
95
                if err != nil {
×
96
                        return nil, nil, nil, err
×
97
                }
×
98
        }
99
        if e2 != nil {
1✔
100
                edge2Ann, err = ChannelUpdateFromEdge(chanInfo, e2)
×
101
                if err != nil {
×
102
                        return nil, nil, nil, err
×
103
                }
×
104
        }
105

106
        return chanAnn, edge1Ann, edge2Ann, nil
1✔
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 {
2✔
116

2✔
117
        switch ann := a.(type) {
2✔
118
        case *lnwire.ChannelAnnouncement1:
×
119
                return validateChannelAnn1(ann)
×
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 {
×
132
        // First, we'll compute the digest (h) which is to be signed by each of
×
133
        // the keys included within the node announcement message. This hash
×
134
        // digest includes all the keys, so the (up to 4 signatures) will
×
135
        // attest to the validity of each of the keys.
×
136
        data, err := a.DataToSign()
×
137
        if err != nil {
×
138
                return err
×
139
        }
×
140
        dataHash := chainhash.DoubleHashB(data)
×
141

×
142
        // First we'll verify that the passed bitcoin key signature is indeed a
×
143
        // signature over the computed hash digest.
×
144
        bitcoinSig1, err := a.BitcoinSig1.ToSignature()
×
145
        if err != nil {
×
146
                return err
×
147
        }
×
148
        bitcoinKey1, err := btcec.ParsePubKey(a.BitcoinKey1[:])
×
149
        if err != nil {
×
150
                return err
×
151
        }
×
152
        if !bitcoinSig1.Verify(dataHash, bitcoinKey1) {
×
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()
×
160
        if err != nil {
×
161
                return err
×
162
        }
×
163
        bitcoinKey2, err := btcec.ParsePubKey(a.BitcoinKey2[:])
×
164
        if err != nil {
×
165
                return err
×
166
        }
×
167
        if !bitcoinSig2.Verify(dataHash, bitcoinKey2) {
×
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()
×
174
        if err != nil {
×
175
                return err
×
176
        }
×
177
        nodeKey1, err := btcec.ParsePubKey(a.NodeID1[:])
×
178
        if err != nil {
×
179
                return err
×
180
        }
×
181
        if !nodeSig1.Verify(dataHash, nodeKey1) {
×
182
                return errors.New("can't verify data in first node signature")
×
183
        }
×
184

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

197
        return nil
×
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