From 5e9365552c85ffa766954dc0b2b6386897bd35e7 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Wed, 2 Jul 2025 01:55:25 +0800 Subject: [PATCH] lnwire: fix encoding `ExtraData` in `DynPropose` Previously we encode all the fields plus extra data to the field `ExtraData`, this is now fixed by encoding only unknown data to extra data. For known records, they are already encoded into the message fields. --- lnwire/dyn_propose.go | 39 +++++++++++++++++++++++++++++++++------ lnwire/test_message.go | 38 +++++++++++++++++++++++++++++--------- 2 files changed, 62 insertions(+), 15 deletions(-) diff --git a/lnwire/dyn_propose.go b/lnwire/dyn_propose.go index af7e8427b..a1c3b4ba0 100644 --- a/lnwire/dyn_propose.go +++ b/lnwire/dyn_propose.go @@ -74,14 +74,23 @@ func (dp *DynPropose) Encode(w *bytes.Buffer, _ uint32) error { return err } - producers := dynProposeRecords(dp) - - err := EncodeMessageExtraData(&dp.ExtraData, producers...) + // Create extra data records. + producers, err := dp.ExtraData.RecordProducers() if err != nil { return err } - return WriteBytes(w, dp.ExtraData) + // Append the known records. + producers = append(producers, dynProposeRecords(dp)...) + + // Encode all records. + var tlvData ExtraOpaqueData + err = tlvData.PackRecords(producers...) + if err != nil { + return err + } + + return WriteBytes(w, tlvData) } // Decode deserializes the serialized DynPropose stored in the passed io.Reader @@ -124,34 +133,52 @@ func (dp *DynPropose) Decode(r io.Reader, _ uint32) error { var rec tlv.RecordT[tlv.TlvType0, tlv.BigSizeT[btcutil.Amount]] rec.Val = dustLimit.Val dp.DustLimit = tlv.SomeRecordT(rec) + delete(typeMap, dp.DustLimit.TlvType()) } if val, ok := typeMap[dp.MaxValueInFlight.TlvType()]; ok && val == nil { var rec tlv.RecordT[tlv.TlvType2, MilliSatoshi] rec.Val = MilliSatoshi(maxValue.Val) dp.MaxValueInFlight = tlv.SomeRecordT(rec) + + delete(typeMap, dp.MaxValueInFlight.TlvType()) } if val, ok := typeMap[dp.HtlcMinimum.TlvType()]; ok && val == nil { var rec tlv.RecordT[tlv.TlvType4, MilliSatoshi] rec.Val = MilliSatoshi(htlcMin.Val) dp.HtlcMinimum = tlv.SomeRecordT(rec) + + delete(typeMap, dp.HtlcMinimum.TlvType()) } if val, ok := typeMap[dp.ChannelReserve.TlvType()]; ok && val == nil { var rec tlv.RecordT[tlv.TlvType6, tlv.BigSizeT[btcutil.Amount]] rec.Val = reserve.Val dp.ChannelReserve = tlv.SomeRecordT(rec) + + delete(typeMap, dp.ChannelReserve.TlvType()) } if val, ok := typeMap[dp.CsvDelay.TlvType()]; ok && val == nil { dp.CsvDelay = tlv.SomeRecordT(csvDelay) + + delete(typeMap, dp.CsvDelay.TlvType()) } if val, ok := typeMap[dp.MaxAcceptedHTLCs.TlvType()]; ok && val == nil { dp.MaxAcceptedHTLCs = tlv.SomeRecordT(maxHtlcs) + + delete(typeMap, dp.MaxAcceptedHTLCs.TlvType()) } if val, ok := typeMap[dp.ChannelType.TlvType()]; ok && val == nil { dp.ChannelType = tlv.SomeRecordT(chanType) + + delete(typeMap, dp.ChannelType.TlvType()) } - if len(tlvRecords) != 0 { - dp.ExtraData = tlvRecords + if len(typeMap) != 0 { + extraData, err := NewExtraOpaqueData(typeMap) + if err != nil { + return err + } + + dp.ExtraData = extraData } return nil diff --git a/lnwire/test_message.go b/lnwire/test_message.go index fe23df9c8..28ffba6c2 100644 --- a/lnwire/test_message.go +++ b/lnwire/test_message.go @@ -815,8 +815,7 @@ var _ TestMessage = (*DynPropose)(nil) // This is part of the TestMessage interface. func (dp *DynPropose) RandTestMessage(t *rapid.T) Message { msg := &DynPropose{ - ChanID: RandChannelID(t), - ExtraData: RandExtraOpaqueData(t, nil), + ChanID: RandChannelID(t), } // Randomly decide which optional fields to include @@ -872,6 +871,21 @@ func (dp *DynPropose) RandTestMessage(t *rapid.T) Message { msg.ChannelType = tlv.SomeRecordT(chanType) } + // Create a tlv type lists to hold all known records which will be + // ignored when creating ExtraData records. + ignoreRecords := fn.NewSet[uint64]() + for i := range uint64(13) { + // Ignore known records. + if i%2 == 0 { + ignoreRecords.Add(i) + } + } + + extraData := RandExtraOpaqueData(t, ignoreRecords) + if len(extraData) > 0 { + msg.ExtraData = extraData + } + return msg } @@ -981,17 +995,23 @@ func (dc *DynCommit) RandTestMessage(t *rapid.T) Message { dp.ChannelType = tlv.SomeRecordT(chanType) } - var extraData ExtraOpaqueData - randData := RandExtraOpaqueData(t, nil) - if len(randData) > 0 { - extraData = randData + // Create a tlv type lists to hold all known records which will be + // ignored when creating ExtraData records. + ignoreRecords := fn.NewSet[uint64]() + for i := range uint64(13) { + ignoreRecords.Add(i) } - - return &DynCommit{ + msg := &DynCommit{ DynPropose: *dp, DynAck: *da, - ExtraData: extraData, } + + extraData := RandExtraOpaqueData(t, ignoreRecords) + if len(extraData) > 0 { + msg.ExtraData = extraData + } + + return msg } // A compile time check to ensure FundingCreated implements the TestMessage