Skip to content

Commit b6b764d

Browse files
committed
lnwire+netann: update ChannelUpdate2
such that all fields are now TLV including the signature.
1 parent 1f71f14 commit b6b764d

File tree

4 files changed

+159
-59
lines changed

4 files changed

+159
-59
lines changed

lnwire/channel_update_2.go

Lines changed: 35 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,6 @@ const (
2222
// HTLCs and other parameters. This message is also used to redeclare initially
2323
// set channel parameters.
2424
type ChannelUpdate2 struct {
25-
// Signature is used to validate the announced data and prove the
26-
// ownership of node id.
27-
Signature Sig
28-
2925
// ChainHash denotes the target chain that this channel was opened
3026
// within. This value should be the genesis hash of the target chain.
3127
// Along with the short channel ID, this uniquely identifies the
@@ -74,28 +70,29 @@ type ChannelUpdate2 struct {
7470
// millionth of a satoshi.
7571
FeeProportionalMillionths tlv.RecordT[tlv.TlvType18, uint32]
7672

77-
// ExtraOpaqueData is the set of data that was appended to this message
78-
// to fill out the full maximum transport message size. These fields can
79-
// be used to specify optional data such as custom TLV fields.
80-
ExtraOpaqueData ExtraOpaqueData
73+
// Signature is used to validate the announced data and prove the
74+
// ownership of node id.
75+
Signature tlv.RecordT[tlv.TlvType160, Sig]
76+
77+
// Any extra fields in the signed range that we do not yet know about,
78+
// but we need to keep them for signature validation and to produce a
79+
// valid message.
80+
ExtraSignedFields
81+
}
82+
83+
// Encode serializes the target ChannelUpdate2 into the passed io.Writer
84+
// observing the protocol version specified.
85+
//
86+
// This is part of the lnwire.Message interface.
87+
func (c *ChannelUpdate2) Encode(w *bytes.Buffer, _ uint32) error {
88+
return EncodePureTLVMessage(c, w)
8189
}
8290

8391
// Decode deserializes a serialized ChannelUpdate2 stored in the passed
8492
// io.Reader observing the specified protocol version.
8593
//
8694
// This is part of the lnwire.Message interface.
8795
func (c *ChannelUpdate2) Decode(r io.Reader, _ uint32) error {
88-
err := ReadElement(r, &c.Signature)
89-
if err != nil {
90-
return err
91-
}
92-
c.Signature.ForceSchnorr()
93-
94-
return c.DecodeTLVRecords(r)
95-
}
96-
97-
// DecodeTLVRecords decodes only the TLV section of the message.
98-
func (c *ChannelUpdate2) DecodeTLVRecords(r io.Reader) error {
9996
// First extract into extra opaque data.
10097
var tlvRecords ExtraOpaqueData
10198
if err := ReadElements(r, &tlvRecords); err != nil {
@@ -111,10 +108,12 @@ func (c *ChannelUpdate2) DecodeTLVRecords(r io.Reader) error {
111108
&secondPeer, &c.CLTVExpiryDelta, &c.HTLCMinimumMsat,
112109
&c.HTLCMaximumMsat, &c.FeeBaseMsat,
113110
&c.FeeProportionalMillionths,
111+
&c.Signature,
114112
)
115113
if err != nil {
116114
return err
117115
}
116+
c.Signature.Val.ForceSchnorr()
118117

119118
// By default, the chain-hash is the bitcoin mainnet genesis block hash.
120119
c.ChainHash.Val = *chaincfg.MainNetParams.GenesisHash
@@ -150,38 +149,21 @@ func (c *ChannelUpdate2) DecodeTLVRecords(r io.Reader) error {
150149
c.FeeProportionalMillionths.Val = defaultFeeProportionalMillionths //nolint:ll
151150
}
152151

153-
if len(tlvRecords) != 0 {
154-
c.ExtraOpaqueData = tlvRecords
155-
}
152+
c.ExtraSignedFields = ExtraSignedFieldsFromTypeMap(typeMap)
156153

157-
return c.ExtraOpaqueData.ValidateTLV()
154+
return nil
158155
}
159156

160-
// Encode serializes the target ChannelUpdate2 into the passed io.Writer
161-
// observing the protocol version specified.
157+
// AllRecords returns all the TLV records for the message. This will include all
158+
// the records we know about along with any that we don't know about but that
159+
// fall in the signed TLV range.
162160
//
163-
// This is part of the lnwire.Message interface.
164-
func (c *ChannelUpdate2) Encode(w *bytes.Buffer, _ uint32) error {
165-
_, err := w.Write(c.Signature.RawBytes())
166-
if err != nil {
167-
return err
168-
}
169-
170-
_, err = c.DataToSign()
171-
if err != nil {
172-
return err
173-
}
174-
175-
return WriteBytes(w, c.ExtraOpaqueData)
176-
}
161+
// NOTE: this is part of the PureTLVMessage interface.
162+
func (c *ChannelUpdate2) AllRecords() []tlv.Record {
163+
var recordProducers []tlv.RecordProducer
177164

178-
// DataToSign is used to retrieve part of the announcement message which should
179-
// be signed. For the ChannelUpdate2 message, this includes the serialised TLV
180-
// records.
181-
func (c *ChannelUpdate2) DataToSign() ([]byte, error) {
182165
// The chain-hash record is only included if it is _not_ equal to the
183166
// bitcoin mainnet genisis block hash.
184-
var recordProducers []tlv.RecordProducer
185167
if !c.ChainHash.Val.IsEqual(chaincfg.MainNetParams.GenesisHash) {
186168
hash := tlv.ZeroRecordT[tlv.TlvType0, [32]byte]()
187169
hash.Val = c.ChainHash.Val
@@ -190,7 +172,7 @@ func (c *ChannelUpdate2) DataToSign() ([]byte, error) {
190172
}
191173

192174
recordProducers = append(recordProducers,
193-
&c.ShortChannelID, &c.BlockHeight,
175+
&c.ShortChannelID, &c.BlockHeight, &c.Signature,
194176
)
195177

196178
// Only include the disable flags if any bit is set.
@@ -225,12 +207,11 @@ func (c *ChannelUpdate2) DataToSign() ([]byte, error) {
225207
)
226208
}
227209

228-
err := EncodeMessageExtraData(&c.ExtraOpaqueData, recordProducers...)
229-
if err != nil {
230-
return nil, err
231-
}
210+
recordProducers = append(recordProducers, RecordsAsProducers(
211+
tlv.MapToRecords(c.ExtraSignedFields),
212+
)...)
232213

233-
return c.ExtraOpaqueData, nil
214+
return ProduceRecordsSorted(recordProducers...)
234215
}
235216

236217
// MsgType returns the integer uniquely identifying this message type on the
@@ -248,14 +229,14 @@ func (c *ChannelUpdate2) SerializedSize() (uint32, error) {
248229
return MessageSerializedSize(c)
249230
}
250231

251-
func (c *ChannelUpdate2) ExtraData() ExtraOpaqueData {
252-
return c.ExtraOpaqueData
253-
}
254-
255232
// A compile time check to ensure ChannelUpdate2 implements the
256233
// lnwire.Message interface.
257234
var _ Message = (*ChannelUpdate2)(nil)
258235

236+
// A compile time check to ensure ChannelUpdate2 implements the
237+
// lnwire.PureTLVMessage interface.
238+
var _ PureTLVMessage = (*ChannelUpdate2)(nil)
239+
259240
// SCID returns the ShortChannelID of the channel that the update applies to.
260241
//
261242
// NOTE: this is part of the ChannelUpdate interface.

lnwire/channel_update_2_test.go

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
package lnwire
2+
3+
import (
4+
"bytes"
5+
"testing"
6+
7+
"github.com/lightningnetwork/lnd/tlv"
8+
"github.com/stretchr/testify/require"
9+
)
10+
11+
// TestChanUpdate2EncodeDecode tests the encoding and decoding of the
12+
// ChannelUpdate2 message using hardcoded byte slices.
13+
func TestChanUpdate2EncodeDecode(t *testing.T) {
14+
t.Parallel()
15+
16+
// We'll create a raw byte stream that represents a valid ChannelUpdate2
17+
// message. This includes the signature and a TLV stream with both known
18+
// and unknown records.
19+
rawBytes := []byte{
20+
// ChainHash record (optional, not mainnet).
21+
0x0, // type.
22+
0x20, // length.
23+
0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1,
24+
0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1,
25+
0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1,
26+
27+
// ShortChannelID record.
28+
0x2, // type.
29+
0x8, // length.
30+
0x0, 0x0, 0x1, 0x0, 0x0, 0x2, 0x0, 0x3, // value.
31+
32+
// BlockHeight record.
33+
0x4, // type.
34+
0x4, // length.
35+
0x0, 0x0, 0x1, 0x0, // value.
36+
37+
// DisabledFlags record.
38+
0x6, // type.
39+
0x1, // length.
40+
0x1, // value.
41+
42+
// SecondPeer record.
43+
0x8, // type.
44+
0x0, // length.
45+
46+
// Unknown odd-type TLV record.
47+
0x9, // type.
48+
0x2, // length.
49+
0xab, 0xcd, // value.
50+
51+
// CLTVExpiryDelta record.
52+
0xa, // type.
53+
0x2, // length.
54+
0x0, 0x10, // value.
55+
56+
// HTLCMinimumMsat record.
57+
0xc, // type.
58+
0x5, // length.
59+
0xfe, 0x0, 0xf, 0x42, 0x40, // value (BigSize: 1_000_000).
60+
61+
// HTLCMaximumMsat record.
62+
0xe, // type.
63+
0x5, // length.
64+
0xfe, 0x0, 0xf, 0x42, 0x40, // value (BigSize: 1_000_000).
65+
66+
// FeeBaseMsat record.
67+
0x10, // type.
68+
0x4, // length.
69+
0x0, 0x0, 0x1, 0x0, // value.
70+
71+
// FeeProportionalMillionths record.
72+
0x12, // type.
73+
0x4, // length.
74+
0x0, 0x0, 0x1, 0x0, // value.
75+
76+
// Extra Opaque Data - Unknown Record.
77+
0x14, // type.
78+
0x2, // length.
79+
0x79, 0x79, // value.
80+
81+
// Signature.
82+
0xa0, // type.
83+
0x40, // length.
84+
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb,
85+
0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
86+
0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
87+
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
88+
0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34,
89+
0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
90+
0x3f, // value
91+
}
92+
93+
secondSignedRangeType := new(bytes.Buffer)
94+
var buf [8]byte
95+
err := tlv.WriteVarInt(
96+
secondSignedRangeType, pureTLVSignedSecondRangeStart+1, &buf,
97+
)
98+
require.NoError(t, err)
99+
rawBytes = append(rawBytes, secondSignedRangeType.Bytes()...) // type.
100+
rawBytes = append(rawBytes, []byte{
101+
0x02, // length.
102+
0x79, 0x79, // value.
103+
}...)
104+
105+
// Now, create a new empty message and decode the raw bytes into it.
106+
msg := &ChannelUpdate2{}
107+
r := bytes.NewReader(rawBytes)
108+
err = msg.Decode(r, 0)
109+
require.NoError(t, err)
110+
111+
// Next, encode the message back into a new byte buffer.
112+
var b bytes.Buffer
113+
err = msg.Encode(&b, 0)
114+
require.NoError(t, err)
115+
116+
// The re-encoded bytes should be exactly the same as the original raw
117+
// bytes.
118+
require.Equal(t, rawBytes, b.Bytes())
119+
}

lnwire/test_message.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -518,7 +518,6 @@ func (c *ChannelUpdate2) RandTestMessage(t *rapid.T) Message {
518518

519519
//nolint:ll
520520
msg := &ChannelUpdate2{
521-
Signature: RandSignature(t),
522521
ChainHash: tlv.NewPrimitiveRecord[tlv.TlvType0, chainhash.Hash](
523522
chainHashObj,
524523
),
@@ -546,10 +545,11 @@ func (c *ChannelUpdate2) RandTestMessage(t *rapid.T) Message {
546545
FeeProportionalMillionths: tlv.NewPrimitiveRecord[tlv.TlvType18, uint32](
547546
feeProportionalMillionths,
548547
),
549-
ExtraOpaqueData: RandExtraOpaqueData(t, nil),
548+
ExtraSignedFields: make(map[uint64][]byte),
550549
}
551550

552-
msg.Signature.ForceSchnorr()
551+
msg.Signature.Val = RandSignature(t)
552+
msg.Signature.Val.ForceSchnorr()
553553

554554
if rapid.Bool().Draw(t, "isSecondPeer") {
555555
msg.SecondPeer = tlv.SomeRecordT(

netann/channel_update.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ func verifyChannelUpdate2Signature(c *lnwire.ChannelUpdate2,
242242
return fmt.Errorf("unable to reconstruct message data: %w", err)
243243
}
244244

245-
nodeSig, err := c.Signature.ToSignature()
245+
nodeSig, err := c.Signature.Val.ToSignature()
246246
if err != nil {
247247
return err
248248
}
@@ -330,7 +330,7 @@ func ChanUpdate2DigestTag() []byte {
330330
// chanUpdate2DigestToSign computes the digest of the ChannelUpdate2 message to
331331
// be signed.
332332
func chanUpdate2DigestToSign(c *lnwire.ChannelUpdate2) ([]byte, error) {
333-
data, err := c.DataToSign()
333+
data, err := lnwire.SerialiseFieldsToSign(c)
334334
if err != nil {
335335
return nil, err
336336
}

0 commit comments

Comments
 (0)