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.
This commit is contained in:
yyforyongyu
2025-07-02 01:55:25 +08:00
parent 61ef83e9c2
commit 5e9365552c
2 changed files with 62 additions and 15 deletions

View File

@@ -74,14 +74,23 @@ func (dp *DynPropose) Encode(w *bytes.Buffer, _ uint32) error {
return err return err
} }
producers := dynProposeRecords(dp) // Create extra data records.
producers, err := dp.ExtraData.RecordProducers()
err := EncodeMessageExtraData(&dp.ExtraData, producers...)
if err != nil { if err != nil {
return err 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 // 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]] var rec tlv.RecordT[tlv.TlvType0, tlv.BigSizeT[btcutil.Amount]]
rec.Val = dustLimit.Val rec.Val = dustLimit.Val
dp.DustLimit = tlv.SomeRecordT(rec) dp.DustLimit = tlv.SomeRecordT(rec)
delete(typeMap, dp.DustLimit.TlvType())
} }
if val, ok := typeMap[dp.MaxValueInFlight.TlvType()]; ok && val == nil { if val, ok := typeMap[dp.MaxValueInFlight.TlvType()]; ok && val == nil {
var rec tlv.RecordT[tlv.TlvType2, MilliSatoshi] var rec tlv.RecordT[tlv.TlvType2, MilliSatoshi]
rec.Val = MilliSatoshi(maxValue.Val) rec.Val = MilliSatoshi(maxValue.Val)
dp.MaxValueInFlight = tlv.SomeRecordT(rec) dp.MaxValueInFlight = tlv.SomeRecordT(rec)
delete(typeMap, dp.MaxValueInFlight.TlvType())
} }
if val, ok := typeMap[dp.HtlcMinimum.TlvType()]; ok && val == nil { if val, ok := typeMap[dp.HtlcMinimum.TlvType()]; ok && val == nil {
var rec tlv.RecordT[tlv.TlvType4, MilliSatoshi] var rec tlv.RecordT[tlv.TlvType4, MilliSatoshi]
rec.Val = MilliSatoshi(htlcMin.Val) rec.Val = MilliSatoshi(htlcMin.Val)
dp.HtlcMinimum = tlv.SomeRecordT(rec) dp.HtlcMinimum = tlv.SomeRecordT(rec)
delete(typeMap, dp.HtlcMinimum.TlvType())
} }
if val, ok := typeMap[dp.ChannelReserve.TlvType()]; ok && val == nil { if val, ok := typeMap[dp.ChannelReserve.TlvType()]; ok && val == nil {
var rec tlv.RecordT[tlv.TlvType6, tlv.BigSizeT[btcutil.Amount]] var rec tlv.RecordT[tlv.TlvType6, tlv.BigSizeT[btcutil.Amount]]
rec.Val = reserve.Val rec.Val = reserve.Val
dp.ChannelReserve = tlv.SomeRecordT(rec) dp.ChannelReserve = tlv.SomeRecordT(rec)
delete(typeMap, dp.ChannelReserve.TlvType())
} }
if val, ok := typeMap[dp.CsvDelay.TlvType()]; ok && val == nil { if val, ok := typeMap[dp.CsvDelay.TlvType()]; ok && val == nil {
dp.CsvDelay = tlv.SomeRecordT(csvDelay) dp.CsvDelay = tlv.SomeRecordT(csvDelay)
delete(typeMap, dp.CsvDelay.TlvType())
} }
if val, ok := typeMap[dp.MaxAcceptedHTLCs.TlvType()]; ok && val == nil { if val, ok := typeMap[dp.MaxAcceptedHTLCs.TlvType()]; ok && val == nil {
dp.MaxAcceptedHTLCs = tlv.SomeRecordT(maxHtlcs) dp.MaxAcceptedHTLCs = tlv.SomeRecordT(maxHtlcs)
delete(typeMap, dp.MaxAcceptedHTLCs.TlvType())
} }
if val, ok := typeMap[dp.ChannelType.TlvType()]; ok && val == nil { if val, ok := typeMap[dp.ChannelType.TlvType()]; ok && val == nil {
dp.ChannelType = tlv.SomeRecordT(chanType) dp.ChannelType = tlv.SomeRecordT(chanType)
delete(typeMap, dp.ChannelType.TlvType())
} }
if len(tlvRecords) != 0 { if len(typeMap) != 0 {
dp.ExtraData = tlvRecords extraData, err := NewExtraOpaqueData(typeMap)
if err != nil {
return err
}
dp.ExtraData = extraData
} }
return nil return nil

View File

@@ -816,7 +816,6 @@ var _ TestMessage = (*DynPropose)(nil)
func (dp *DynPropose) RandTestMessage(t *rapid.T) Message { func (dp *DynPropose) RandTestMessage(t *rapid.T) Message {
msg := &DynPropose{ msg := &DynPropose{
ChanID: RandChannelID(t), ChanID: RandChannelID(t),
ExtraData: RandExtraOpaqueData(t, nil),
} }
// Randomly decide which optional fields to include // Randomly decide which optional fields to include
@@ -872,6 +871,21 @@ func (dp *DynPropose) RandTestMessage(t *rapid.T) Message {
msg.ChannelType = tlv.SomeRecordT(chanType) 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 return msg
} }
@@ -981,17 +995,23 @@ func (dc *DynCommit) RandTestMessage(t *rapid.T) Message {
dp.ChannelType = tlv.SomeRecordT(chanType) dp.ChannelType = tlv.SomeRecordT(chanType)
} }
var extraData ExtraOpaqueData // Create a tlv type lists to hold all known records which will be
randData := RandExtraOpaqueData(t, nil) // ignored when creating ExtraData records.
if len(randData) > 0 { ignoreRecords := fn.NewSet[uint64]()
extraData = randData for i := range uint64(13) {
ignoreRecords.Add(i)
} }
msg := &DynCommit{
return &DynCommit{
DynPropose: *dp, DynPropose: *dp,
DynAck: *da, 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 // A compile time check to ensure FundingCreated implements the TestMessage