From c6861770debd6996a4b6374bec4457486909ee3e Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Fri, 13 Sep 2024 16:27:59 -0700 Subject: [PATCH 01/12] lnwire: remove no longer used initiator field --- lnwire/dyn_propose.go | 12 +----------- lnwire/test_message.go | 1 - 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/lnwire/dyn_propose.go b/lnwire/dyn_propose.go index cc19ec394f4..4fcbaa40952 100644 --- a/lnwire/dyn_propose.go +++ b/lnwire/dyn_propose.go @@ -52,12 +52,6 @@ type DynPropose struct { // re-negotiate. ChanID ChannelID - // Initiator is a byte that identifies whether this message was sent as - // the initiator of a dynamic commitment negotiation or the responder - // of a dynamic commitment negotiation. bool true indicates it is the - // initiator - Initiator bool - // DustLimit, if not nil, proposes a change to the dust_limit_satoshis // for the sender's commitment transaction. DustLimit fn.Option[btcutil.Amount] @@ -195,10 +189,6 @@ func (dp *DynPropose) Encode(w *bytes.Buffer, _ uint32) error { return err } - if err := WriteBool(w, dp.Initiator); err != nil { - return err - } - return WriteBytes(w, dp.ExtraData) } @@ -209,7 +199,7 @@ func (dp *DynPropose) Encode(w *bytes.Buffer, _ uint32) error { // This is a part of the lnwire.Message interface. func (dp *DynPropose) Decode(r io.Reader, _ uint32) error { // Parse out the only required field. - if err := ReadElements(r, &dp.ChanID, &dp.Initiator); err != nil { + if err := ReadElements(r, &dp.ChanID); err != nil { return err } diff --git a/lnwire/test_message.go b/lnwire/test_message.go index 9d086c8688a..064c8885b7b 100644 --- a/lnwire/test_message.go +++ b/lnwire/test_message.go @@ -817,7 +817,6 @@ var _ TestMessage = (*DynPropose)(nil) func (dp *DynPropose) RandTestMessage(t *rapid.T) Message { msg := &DynPropose{ ChanID: RandChannelID(t), - Initiator: rapid.Bool().Draw(t, "initiator"), ExtraData: RandExtraOpaqueData(t, nil), } From 60887ad3ef3c2af56576c44ac99b9a606659fae3 Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Thu, 12 Sep 2024 14:52:09 -0700 Subject: [PATCH 02/12] lnwire: add signature to DynAck --- lnwire/dyn_ack.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lnwire/dyn_ack.go b/lnwire/dyn_ack.go index 1cc57e955a9..1e25e16759c 100644 --- a/lnwire/dyn_ack.go +++ b/lnwire/dyn_ack.go @@ -24,6 +24,10 @@ type DynAck struct { // a dynamic commitment negotiation ChanID ChannelID + // Sig is a signature that acknowledges and approves the parameters + // that were requested in the DynPropose + Sig Sig + // LocalNonce is an optional field that is transmitted when accepting // a dynamic commitment upgrade to Taproot Channels. This nonce will be // used to verify the first commitment transaction signature. This will @@ -54,6 +58,10 @@ func (da *DynAck) Encode(w *bytes.Buffer, _ uint32) error { return err } + if err := WriteSig(w, da.Sig); err != nil { + return err + } + var tlvRecords []tlv.Record da.LocalNonce.WhenSome(func(nonce Musig2Nonce) { tlvRecords = append( @@ -88,7 +96,7 @@ func (da *DynAck) Encode(w *bytes.Buffer, _ uint32) error { // This is a part of the lnwire.Message interface. func (da *DynAck) Decode(r io.Reader, _ uint32) error { // Parse out main message. - if err := ReadElements(r, &da.ChanID); err != nil { + if err := ReadElements(r, &da.ChanID, &da.Sig); err != nil { return err } From 42089b19d6e0f86a7be82567942f80ca56c2fd53 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Wed, 25 Jun 2025 00:42:33 +0800 Subject: [PATCH 03/12] lnwire: add DynCommit message to match spec --- lnwire/dyn_commit.go | 247 +++++++++++++++++++++++++++++++++++++++++++ lnwire/fuzz_test.go | 6 ++ lnwire/message.go | 5 + 3 files changed, 258 insertions(+) create mode 100644 lnwire/dyn_commit.go diff --git a/lnwire/dyn_commit.go b/lnwire/dyn_commit.go new file mode 100644 index 00000000000..55159837980 --- /dev/null +++ b/lnwire/dyn_commit.go @@ -0,0 +1,247 @@ +package lnwire + +import ( + "bytes" + "io" + + "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/btcutil" + "github.com/lightningnetwork/lnd/fn/v2" + "github.com/lightningnetwork/lnd/lnwallet/chainfee" + "github.com/lightningnetwork/lnd/tlv" +) + +// DynCommit is a composite message that is used to irrefutably execute a +// dynamic commitment update. +type DynCommit struct { + // DynPropose is an embedded version of the original DynPropose message + // that initiated this negotiation. + DynPropose + + // DynAck is an embedded version of the original DynAck message that + // countersigned this negotiation. + DynAck + + // ExtraData is the set of data that was appended to this message to + // fill out the full maximum transport message size. These fields can + // be used to specify optional data such as custom TLV fields. + ExtraData ExtraOpaqueData +} + +// A compile time check to ensure DynAck implements the lnwire.Message +// interface. +var _ Message = (*DynCommit)(nil) + +// Encode serializes the target DynAck into the passed io.Writer. Serialization +// will observe the rules defined by the passed protocol version. +// +// This is a part of the lnwire.Message interface. +func (dc *DynCommit) Encode(w *bytes.Buffer, _ uint32) error { + if err := WriteChannelID(w, dc.DynPropose.ChanID); err != nil { + return err + } + + if err := WriteSig(w, dc.Sig); err != nil { + return err + } + + var tlvRecords []tlv.Record + dc.DustLimit.WhenSome(func(dl btcutil.Amount) { + protoSats := uint64(dl) + tlvRecords = append( + tlvRecords, tlv.MakePrimitiveRecord( + DPDustLimitSatoshis, &protoSats, + ), + ) + }) + dc.MaxValueInFlight.WhenSome(func(max MilliSatoshi) { + protoSats := uint64(max) + tlvRecords = append( + tlvRecords, tlv.MakePrimitiveRecord( + DPMaxHtlcValueInFlightMsat, &protoSats, + ), + ) + }) + dc.ChannelReserve.WhenSome(func(min btcutil.Amount) { + channelReserve := uint64(min) + tlvRecords = append( + tlvRecords, tlv.MakePrimitiveRecord( + DPChannelReserveSatoshis, &channelReserve, + ), + ) + }) + dc.CsvDelay.WhenSome(func(wait uint16) { + tlvRecords = append( + tlvRecords, tlv.MakePrimitiveRecord( + DPToSelfDelay, &wait, + ), + ) + }) + dc.MaxAcceptedHTLCs.WhenSome(func(max uint16) { + tlvRecords = append( + tlvRecords, tlv.MakePrimitiveRecord( + DPMaxAcceptedHtlcs, &max, + ), + ) + }) + dc.FundingKey.WhenSome(func(key btcec.PublicKey) { + keyScratch := &key + tlvRecords = append( + tlvRecords, tlv.MakePrimitiveRecord( + DPFundingPubkey, &keyScratch, + ), + ) + }) + dc.ChannelType.WhenSome(func(ty ChannelType) { + tlvRecords = append( + tlvRecords, tlv.MakeDynamicRecord( + DPChannelType, &ty, + ty.featureBitLen, + channelTypeEncoder, channelTypeDecoder, + ), + ) + }) + dc.KickoffFeerate.WhenSome(func(kickoffFeerate chainfee.SatPerKWeight) { + protoSats := uint32(kickoffFeerate) + tlvRecords = append( + tlvRecords, tlv.MakePrimitiveRecord( + DPKickoffFeerate, &protoSats, + ), + ) + }) + tlv.SortRecords(tlvRecords) + + tlvStream, err := tlv.NewStream(tlvRecords...) + if err != nil { + return err + } + + var extraBytesWriter bytes.Buffer + if err := tlvStream.Encode(&extraBytesWriter); err != nil { + return err + } + + dc.ExtraData = ExtraOpaqueData(extraBytesWriter.Bytes()) + + return WriteBytes(w, dc.ExtraData) +} + +// Decode deserializes the serialized DynCommit stored in the passed io.Reader +// into the target DynAck using the deserialization rules defined by the passed +// protocol version. +// +// This is a part of the lnwire.Message interface. +func (dc *DynCommit) Decode(r io.Reader, _ uint32) error { + // Parse out main message. + if err := ReadElements(r, &dc.DynPropose.ChanID, &dc.Sig); err != nil { + return err + } + dc.DynAck.ChanID = dc.DynPropose.ChanID + + // Parse out TLV records. + var tlvRecords ExtraOpaqueData + if err := ReadElement(r, &tlvRecords); err != nil { + return err + } + + // Prepare receiving buffers to be filled by TLV extraction. + var dustLimitScratch uint64 + dustLimit := tlv.MakePrimitiveRecord( + DPDustLimitSatoshis, &dustLimitScratch, + ) + + var maxValueScratch uint64 + maxValue := tlv.MakePrimitiveRecord( + DPMaxHtlcValueInFlightMsat, &maxValueScratch, + ) + + var reserveScratch uint64 + reserve := tlv.MakePrimitiveRecord( + DPChannelReserveSatoshis, &reserveScratch, + ) + + var csvDelayScratch uint16 + csvDelay := tlv.MakePrimitiveRecord(DPToSelfDelay, &csvDelayScratch) + + var maxHtlcsScratch uint16 + maxHtlcs := tlv.MakePrimitiveRecord( + DPMaxAcceptedHtlcs, &maxHtlcsScratch, + ) + + var fundingKeyScratch *btcec.PublicKey + fundingKey := tlv.MakePrimitiveRecord( + DPFundingPubkey, &fundingKeyScratch, + ) + + var chanTypeScratch ChannelType + chanType := tlv.MakeDynamicRecord( + DPChannelType, &chanTypeScratch, chanTypeScratch.featureBitLen, + channelTypeEncoder, channelTypeDecoder, + ) + + var kickoffFeerateScratch uint32 + kickoffFeerate := tlv.MakePrimitiveRecord( + DPKickoffFeerate, &kickoffFeerateScratch, + ) + + // Create set of Records to read TLV bytestream into. + records := []tlv.Record{ + dustLimit, maxValue, reserve, csvDelay, maxHtlcs, fundingKey, + chanType, kickoffFeerate, + } + tlv.SortRecords(records) + + // Read TLV stream into record set. + extraBytesReader := bytes.NewReader(tlvRecords) + tlvStream, err := tlv.NewStream(records...) + if err != nil { + return err + } + typeMap, err := tlvStream.DecodeWithParsedTypesP2P(extraBytesReader) + if err != nil { + return err + } + + // Check the results of the TLV Stream decoding and appropriately set + // message fields. + if val, ok := typeMap[DPDustLimitSatoshis]; ok && val == nil { + dc.DustLimit = fn.Some(btcutil.Amount(dustLimitScratch)) + } + if val, ok := typeMap[DPMaxHtlcValueInFlightMsat]; ok && val == nil { + dc.MaxValueInFlight = fn.Some(MilliSatoshi(maxValueScratch)) + } + if val, ok := typeMap[DPChannelReserveSatoshis]; ok && val == nil { + dc.ChannelReserve = fn.Some(btcutil.Amount(reserveScratch)) + } + if val, ok := typeMap[DPToSelfDelay]; ok && val == nil { + dc.CsvDelay = fn.Some(csvDelayScratch) + } + if val, ok := typeMap[DPMaxAcceptedHtlcs]; ok && val == nil { + dc.MaxAcceptedHTLCs = fn.Some(maxHtlcsScratch) + } + if val, ok := typeMap[DPFundingPubkey]; ok && val == nil { + dc.FundingKey = fn.Some(*fundingKeyScratch) + } + if val, ok := typeMap[DPChannelType]; ok && val == nil { + dc.ChannelType = fn.Some(chanTypeScratch) + } + if val, ok := typeMap[DPKickoffFeerate]; ok && val == nil { + dc.KickoffFeerate = fn.Some( + chainfee.SatPerKWeight(kickoffFeerateScratch), + ) + } + + if len(tlvRecords) != 0 { + dc.ExtraData = tlvRecords + } + + return nil +} + +// MsgType returns the MessageType code which uniquely identifies this message +// as a DynCommit on the wire. +// +// This is part of the lnwire.Message interface. +func (dc *DynCommit) MsgType() MessageType { + return MsgDynCommit +} diff --git a/lnwire/fuzz_test.go b/lnwire/fuzz_test.go index e608eb9b0bc..054af585cf5 100644 --- a/lnwire/fuzz_test.go +++ b/lnwire/fuzz_test.go @@ -452,6 +452,12 @@ func FuzzDynAck(f *testing.F) { }) } +func FuzzDynCommit(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + wireMsgHarness(t, data, MsgDynCommit) + }) +} + func FuzzKickoffSig(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { wireMsgHarness(t, data, MsgKickoffSig) diff --git a/lnwire/message.go b/lnwire/message.go index ea480075a1a..a36359f0bc3 100644 --- a/lnwire/message.go +++ b/lnwire/message.go @@ -44,6 +44,7 @@ const ( MsgDynPropose = 111 MsgDynAck = 113 MsgDynReject = 115 + MsgDynCommit = 117 MsgUpdateAddHTLC = 128 MsgUpdateFulfillHTLC = 130 MsgUpdateFailHTLC = 131 @@ -140,6 +141,8 @@ func (t MessageType) String() string { return "DynAck" case MsgDynReject: return "DynReject" + case MsgDynCommit: + return "DynCommit" case MsgKickoffSig: return "KickoffSig" case MsgUpdateAddHTLC: @@ -300,6 +303,8 @@ func makeEmptyMessage(msgType MessageType) (Message, error) { msg = &DynAck{} case MsgDynReject: msg = &DynReject{} + case MsgDynCommit: + msg = &DynCommit{} case MsgKickoffSig: msg = &KickoffSig{} case MsgUpdateAddHTLC: From 36f53d74ab05931362b05f2e4f93efd16cfb3f4b Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Fri, 13 Sep 2024 16:25:19 -0700 Subject: [PATCH 04/12] lnwire: add convenience functions for protocol validation --- lnwire/dyn_propose.go | 84 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/lnwire/dyn_propose.go b/lnwire/dyn_propose.go index 4fcbaa40952..3f659986d1a 100644 --- a/lnwire/dyn_propose.go +++ b/lnwire/dyn_propose.go @@ -318,3 +318,87 @@ func (dp *DynPropose) MsgType() MessageType { func (dp *DynPropose) SerializedSize() (uint32, error) { return MessageSerializedSize(dp) } + +// SerializeTlvData takes just the TLV data of DynPropose (which covers all of +// the parameters on deck for changing) and serializes just this component. The +// main purpose of this is to make it easier to validate the DynAck signature. +func (dp *DynPropose) SerializeTlvData() ([]byte, error) { + var tlvRecords []tlv.Record + dp.DustLimit.WhenSome(func(dl btcutil.Amount) { + protoSats := uint64(dl) + tlvRecords = append( + tlvRecords, tlv.MakePrimitiveRecord( + DPDustLimitSatoshis, &protoSats, + ), + ) + }) + dp.MaxValueInFlight.WhenSome(func(max MilliSatoshi) { + protoSats := uint64(max) + tlvRecords = append( + tlvRecords, tlv.MakePrimitiveRecord( + DPMaxHtlcValueInFlightMsat, &protoSats, + ), + ) + }) + dp.ChannelReserve.WhenSome(func(min btcutil.Amount) { + channelReserve := uint64(min) + tlvRecords = append( + tlvRecords, tlv.MakePrimitiveRecord( + DPChannelReserveSatoshis, &channelReserve, + ), + ) + }) + dp.CsvDelay.WhenSome(func(wait uint16) { + tlvRecords = append( + tlvRecords, tlv.MakePrimitiveRecord( + DPToSelfDelay, &wait, + ), + ) + }) + dp.MaxAcceptedHTLCs.WhenSome(func(max uint16) { + tlvRecords = append( + tlvRecords, tlv.MakePrimitiveRecord( + DPMaxAcceptedHtlcs, &max, + ), + ) + }) + dp.FundingKey.WhenSome(func(key btcec.PublicKey) { + keyScratch := &key + tlvRecords = append( + tlvRecords, tlv.MakePrimitiveRecord( + DPFundingPubkey, &keyScratch, + ), + ) + }) + dp.ChannelType.WhenSome(func(ty ChannelType) { + tlvRecords = append( + tlvRecords, tlv.MakeDynamicRecord( + DPChannelType, &ty, + ty.featureBitLen, + channelTypeEncoder, channelTypeDecoder, + ), + ) + }) + dp.KickoffFeerate.WhenSome(func(kickoffFeerate chainfee.SatPerKWeight) { + protoSats := uint32(kickoffFeerate) + tlvRecords = append( + tlvRecords, tlv.MakePrimitiveRecord( + DPKickoffFeerate, &protoSats, + ), + ) + }) + tlv.SortRecords(tlvRecords) + + tlvStream, err := tlv.NewStream(tlvRecords...) + if err != nil { + return nil, err + } + + var outBuf bytes.Buffer + err = tlvStream.Encode(&outBuf) + if err != nil { + return nil, err + } + + return outBuf.Bytes(), nil +} From cbca5b115202e24c184774c16b78d14a43a62e81 Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Mon, 7 Oct 2024 15:37:30 +0200 Subject: [PATCH 05/12] lnwire: remove kickoff feerate from propose/commit --- lnwire/dyn_commit.go | 21 +-------------------- lnwire/dyn_propose.go | 38 +------------------------------------- lnwire/test_message.go | 9 --------- 3 files changed, 2 insertions(+), 66 deletions(-) diff --git a/lnwire/dyn_commit.go b/lnwire/dyn_commit.go index 55159837980..1b9038c5db1 100644 --- a/lnwire/dyn_commit.go +++ b/lnwire/dyn_commit.go @@ -7,7 +7,6 @@ import ( "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcutil" "github.com/lightningnetwork/lnd/fn/v2" - "github.com/lightningnetwork/lnd/lnwallet/chainfee" "github.com/lightningnetwork/lnd/tlv" ) @@ -101,14 +100,6 @@ func (dc *DynCommit) Encode(w *bytes.Buffer, _ uint32) error { ), ) }) - dc.KickoffFeerate.WhenSome(func(kickoffFeerate chainfee.SatPerKWeight) { - protoSats := uint32(kickoffFeerate) - tlvRecords = append( - tlvRecords, tlv.MakePrimitiveRecord( - DPKickoffFeerate, &protoSats, - ), - ) - }) tlv.SortRecords(tlvRecords) tlvStream, err := tlv.NewStream(tlvRecords...) @@ -179,15 +170,10 @@ func (dc *DynCommit) Decode(r io.Reader, _ uint32) error { channelTypeEncoder, channelTypeDecoder, ) - var kickoffFeerateScratch uint32 - kickoffFeerate := tlv.MakePrimitiveRecord( - DPKickoffFeerate, &kickoffFeerateScratch, - ) - // Create set of Records to read TLV bytestream into. records := []tlv.Record{ dustLimit, maxValue, reserve, csvDelay, maxHtlcs, fundingKey, - chanType, kickoffFeerate, + chanType, } tlv.SortRecords(records) @@ -225,11 +211,6 @@ func (dc *DynCommit) Decode(r io.Reader, _ uint32) error { if val, ok := typeMap[DPChannelType]; ok && val == nil { dc.ChannelType = fn.Some(chanTypeScratch) } - if val, ok := typeMap[DPKickoffFeerate]; ok && val == nil { - dc.KickoffFeerate = fn.Some( - chainfee.SatPerKWeight(kickoffFeerateScratch), - ) - } if len(tlvRecords) != 0 { dc.ExtraData = tlvRecords diff --git a/lnwire/dyn_propose.go b/lnwire/dyn_propose.go index 3f659986d1a..a1f12731845 100644 --- a/lnwire/dyn_propose.go +++ b/lnwire/dyn_propose.go @@ -7,7 +7,6 @@ import ( "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcutil" "github.com/lightningnetwork/lnd/fn/v2" - "github.com/lightningnetwork/lnd/lnwallet/chainfee" "github.com/lightningnetwork/lnd/tlv" ) @@ -39,10 +38,6 @@ const ( // DPChannelType is the TLV type number that identifies the record for // DynPropose.ChannelType. DPChannelType tlv.Type = 6 - - // DPKickoffFeerate is the TLV type number that identifies the record - // for DynPropose.KickoffFeerate. - DPKickoffFeerate tlv.Type = 7 ) // DynPropose is a message that is sent during a dynamic commitments negotiation @@ -80,11 +75,6 @@ type DynPropose struct { // parameter. ChannelType fn.Option[ChannelType] - // KickoffFeerate proposes the fee rate in satoshis per kw that it - // is offering for a ChannelType conversion that requires a kickoff - // transaction. - KickoffFeerate fn.Option[chainfee.SatPerKWeight] - // ExtraData is the set of data that was appended to this message to // fill out the full maximum transport message size. These fields can // be used to specify optional data such as custom TLV fields. @@ -164,14 +154,6 @@ func (dp *DynPropose) Encode(w *bytes.Buffer, _ uint32) error { ), ) }) - dp.KickoffFeerate.WhenSome(func(kickoffFeerate chainfee.SatPerKWeight) { - protoSats := uint32(kickoffFeerate) - tlvRecords = append( - tlvRecords, tlv.MakePrimitiveRecord( - DPKickoffFeerate, &protoSats, - ), - ) - }) tlv.SortRecords(tlvRecords) tlvStream, err := tlv.NewStream(tlvRecords...) @@ -244,15 +226,10 @@ func (dp *DynPropose) Decode(r io.Reader, _ uint32) error { channelTypeEncoder, channelTypeDecoder, ) - var kickoffFeerateScratch uint32 - kickoffFeerate := tlv.MakePrimitiveRecord( - DPKickoffFeerate, &kickoffFeerateScratch, - ) - // Create set of Records to read TLV bytestream into. records := []tlv.Record{ dustLimit, maxValue, reserve, csvDelay, maxHtlcs, fundingKey, - chanType, kickoffFeerate, + chanType, } tlv.SortRecords(records) @@ -291,11 +268,6 @@ func (dp *DynPropose) Decode(r io.Reader, _ uint32) error { if val, ok := typeMap[DPChannelType]; ok && val == nil { dp.ChannelType = fn.Some(chanTypeScratch) } - if val, ok := typeMap[DPKickoffFeerate]; ok && val == nil { - dp.KickoffFeerate = fn.Some( - chainfee.SatPerKWeight(kickoffFeerateScratch), - ) - } if len(tlvRecords) != 0 { dp.ExtraData = tlvRecords @@ -379,14 +351,6 @@ func (dp *DynPropose) SerializeTlvData() ([]byte, error) { ), ) }) - dp.KickoffFeerate.WhenSome(func(kickoffFeerate chainfee.SatPerKWeight) { - protoSats := uint32(kickoffFeerate) - tlvRecords = append( - tlvRecords, tlv.MakePrimitiveRecord( - DPKickoffFeerate, &protoSats, - ), - ) - }) tlv.SortRecords(tlvRecords) tlvStream, err := tlv.NewStream(tlvRecords...) diff --git a/lnwire/test_message.go b/lnwire/test_message.go index 064c8885b7b..3df32c295ff 100644 --- a/lnwire/test_message.go +++ b/lnwire/test_message.go @@ -10,7 +10,6 @@ import ( "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/lightningnetwork/lnd/fn/v2" - "github.com/lightningnetwork/lnd/lnwallet/chainfee" "github.com/lightningnetwork/lnd/tlv" "github.com/stretchr/testify/require" "pgregory.net/rapid" @@ -832,7 +831,6 @@ func (dp *DynPropose) RandTestMessage(t *rapid.T) Message { ) includeFundingKey := rapid.Bool().Draw(t, "includeFundingKey") includeChannelType := rapid.Bool().Draw(t, "includeChannelType") - includeKickoffFeerate := rapid.Bool().Draw(t, "includeKickoffFeerate") // Generate random values for each included field if includeDustLimit { @@ -868,13 +866,6 @@ func (dp *DynPropose) RandTestMessage(t *rapid.T) Message { msg.ChannelType = fn.Some(*RandChannelType(t)) } - if includeKickoffFeerate { - kf := chainfee.SatPerKWeight(rapid.Uint32().Draw( - t, "kickoffFeerate"), - ) - msg.KickoffFeerate = fn.Some(kf) - } - return msg } From f40530e4f4c3dd6aec5d483e0a95c43f9a1c6c5f Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Tue, 15 Oct 2024 19:55:11 -0600 Subject: [PATCH 06/12] lnwire: remove FundingKey from DynPropose and DynCommit --- lnwire/dyn_commit.go | 20 +------------------- lnwire/dyn_propose.go | 36 +----------------------------------- lnwire/test_message.go | 5 ----- 3 files changed, 2 insertions(+), 59 deletions(-) diff --git a/lnwire/dyn_commit.go b/lnwire/dyn_commit.go index 1b9038c5db1..bc0eb2fee46 100644 --- a/lnwire/dyn_commit.go +++ b/lnwire/dyn_commit.go @@ -4,7 +4,6 @@ import ( "bytes" "io" - "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcutil" "github.com/lightningnetwork/lnd/fn/v2" "github.com/lightningnetwork/lnd/tlv" @@ -83,14 +82,6 @@ func (dc *DynCommit) Encode(w *bytes.Buffer, _ uint32) error { ), ) }) - dc.FundingKey.WhenSome(func(key btcec.PublicKey) { - keyScratch := &key - tlvRecords = append( - tlvRecords, tlv.MakePrimitiveRecord( - DPFundingPubkey, &keyScratch, - ), - ) - }) dc.ChannelType.WhenSome(func(ty ChannelType) { tlvRecords = append( tlvRecords, tlv.MakeDynamicRecord( @@ -159,11 +150,6 @@ func (dc *DynCommit) Decode(r io.Reader, _ uint32) error { DPMaxAcceptedHtlcs, &maxHtlcsScratch, ) - var fundingKeyScratch *btcec.PublicKey - fundingKey := tlv.MakePrimitiveRecord( - DPFundingPubkey, &fundingKeyScratch, - ) - var chanTypeScratch ChannelType chanType := tlv.MakeDynamicRecord( DPChannelType, &chanTypeScratch, chanTypeScratch.featureBitLen, @@ -172,8 +158,7 @@ func (dc *DynCommit) Decode(r io.Reader, _ uint32) error { // Create set of Records to read TLV bytestream into. records := []tlv.Record{ - dustLimit, maxValue, reserve, csvDelay, maxHtlcs, fundingKey, - chanType, + dustLimit, maxValue, reserve, csvDelay, maxHtlcs, chanType, } tlv.SortRecords(records) @@ -205,9 +190,6 @@ func (dc *DynCommit) Decode(r io.Reader, _ uint32) error { if val, ok := typeMap[DPMaxAcceptedHtlcs]; ok && val == nil { dc.MaxAcceptedHTLCs = fn.Some(maxHtlcsScratch) } - if val, ok := typeMap[DPFundingPubkey]; ok && val == nil { - dc.FundingKey = fn.Some(*fundingKeyScratch) - } if val, ok := typeMap[DPChannelType]; ok && val == nil { dc.ChannelType = fn.Some(chanTypeScratch) } diff --git a/lnwire/dyn_propose.go b/lnwire/dyn_propose.go index a1f12731845..5b200b49245 100644 --- a/lnwire/dyn_propose.go +++ b/lnwire/dyn_propose.go @@ -4,7 +4,6 @@ import ( "bytes" "io" - "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcutil" "github.com/lightningnetwork/lnd/fn/v2" "github.com/lightningnetwork/lnd/tlv" @@ -31,10 +30,6 @@ const ( // for DynPropose.MaxAcceptedHTLCs. DPMaxAcceptedHtlcs tlv.Type = 4 - // DPFundingPubkey is the TLV type number that identifies the record for - // DynPropose.FundingKey. - DPFundingPubkey tlv.Type = 5 - // DPChannelType is the TLV type number that identifies the record for // DynPropose.ChannelType. DPChannelType tlv.Type = 6 @@ -67,10 +62,6 @@ type DynPropose struct { // max_accepted_htlcs limit of the sender. MaxAcceptedHTLCs fn.Option[uint16] - // FundingKey, if not nil, proposes a change to the funding_pubkey - // parameter of the sender. - FundingKey fn.Option[btcec.PublicKey] - // ChannelType, if not nil, proposes a change to the channel_type // parameter. ChannelType fn.Option[ChannelType] @@ -137,14 +128,6 @@ func (dp *DynPropose) Encode(w *bytes.Buffer, _ uint32) error { ), ) }) - dp.FundingKey.WhenSome(func(key btcec.PublicKey) { - keyScratch := &key - tlvRecords = append( - tlvRecords, tlv.MakePrimitiveRecord( - DPFundingPubkey, &keyScratch, - ), - ) - }) dp.ChannelType.WhenSome(func(ty ChannelType) { tlvRecords = append( tlvRecords, tlv.MakeDynamicRecord( @@ -215,11 +198,6 @@ func (dp *DynPropose) Decode(r io.Reader, _ uint32) error { DPMaxAcceptedHtlcs, &maxHtlcsScratch, ) - var fundingKeyScratch *btcec.PublicKey - fundingKey := tlv.MakePrimitiveRecord( - DPFundingPubkey, &fundingKeyScratch, - ) - var chanTypeScratch ChannelType chanType := tlv.MakeDynamicRecord( DPChannelType, &chanTypeScratch, chanTypeScratch.featureBitLen, @@ -228,8 +206,7 @@ func (dp *DynPropose) Decode(r io.Reader, _ uint32) error { // Create set of Records to read TLV bytestream into. records := []tlv.Record{ - dustLimit, maxValue, reserve, csvDelay, maxHtlcs, fundingKey, - chanType, + dustLimit, maxValue, reserve, csvDelay, maxHtlcs, chanType, } tlv.SortRecords(records) @@ -262,9 +239,6 @@ func (dp *DynPropose) Decode(r io.Reader, _ uint32) error { if val, ok := typeMap[DPMaxAcceptedHtlcs]; ok && val == nil { dp.MaxAcceptedHTLCs = fn.Some(maxHtlcsScratch) } - if val, ok := typeMap[DPFundingPubkey]; ok && val == nil { - dp.FundingKey = fn.Some(*fundingKeyScratch) - } if val, ok := typeMap[DPChannelType]; ok && val == nil { dp.ChannelType = fn.Some(chanTypeScratch) } @@ -334,14 +308,6 @@ func (dp *DynPropose) SerializeTlvData() ([]byte, error) { ), ) }) - dp.FundingKey.WhenSome(func(key btcec.PublicKey) { - keyScratch := &key - tlvRecords = append( - tlvRecords, tlv.MakePrimitiveRecord( - DPFundingPubkey, &keyScratch, - ), - ) - }) dp.ChannelType.WhenSome(func(ty ChannelType) { tlvRecords = append( tlvRecords, tlv.MakeDynamicRecord( diff --git a/lnwire/test_message.go b/lnwire/test_message.go index 3df32c295ff..4cf9bb0cdde 100644 --- a/lnwire/test_message.go +++ b/lnwire/test_message.go @@ -829,7 +829,6 @@ func (dp *DynPropose) RandTestMessage(t *rapid.T) Message { includeMaxAcceptedHTLCs := rapid.Bool().Draw( t, "includeMaxAcceptedHTLCs", ) - includeFundingKey := rapid.Bool().Draw(t, "includeFundingKey") includeChannelType := rapid.Bool().Draw(t, "includeChannelType") // Generate random values for each included field @@ -858,10 +857,6 @@ func (dp *DynPropose) RandTestMessage(t *rapid.T) Message { msg.MaxAcceptedHTLCs = fn.Some(mah) } - if includeFundingKey { - msg.FundingKey = fn.Some(*RandPubKey(t)) - } - if includeChannelType { msg.ChannelType = fn.Some(*RandChannelType(t)) } From 72582d4acca4d4adade100f42e76c2204764517f Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Tue, 15 Oct 2024 20:34:17 -0600 Subject: [PATCH 07/12] lnwire: add HtlcMinimum to DynPropose and DynCommit --- lnwire/dyn_commit.go | 19 ++++++++++++++++++- lnwire/dyn_propose.go | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/lnwire/dyn_commit.go b/lnwire/dyn_commit.go index bc0eb2fee46..f65020371f4 100644 --- a/lnwire/dyn_commit.go +++ b/lnwire/dyn_commit.go @@ -60,6 +60,14 @@ func (dc *DynCommit) Encode(w *bytes.Buffer, _ uint32) error { ), ) }) + dc.HtlcMinimum.WhenSome(func(min MilliSatoshi) { + protoSats := uint64(min) + tlvRecords = append( + tlvRecords, tlv.MakePrimitiveRecord( + DPHtlcMinimumMsat, &protoSats, + ), + ) + }) dc.ChannelReserve.WhenSome(func(min btcutil.Amount) { channelReserve := uint64(min) tlvRecords = append( @@ -137,6 +145,11 @@ func (dc *DynCommit) Decode(r io.Reader, _ uint32) error { DPMaxHtlcValueInFlightMsat, &maxValueScratch, ) + var htlcMinScratch uint64 + htlcMin := tlv.MakePrimitiveRecord( + DPHtlcMinimumMsat, &htlcMinScratch, + ) + var reserveScratch uint64 reserve := tlv.MakePrimitiveRecord( DPChannelReserveSatoshis, &reserveScratch, @@ -158,7 +171,8 @@ func (dc *DynCommit) Decode(r io.Reader, _ uint32) error { // Create set of Records to read TLV bytestream into. records := []tlv.Record{ - dustLimit, maxValue, reserve, csvDelay, maxHtlcs, chanType, + dustLimit, maxValue, htlcMin, reserve, csvDelay, maxHtlcs, + chanType, } tlv.SortRecords(records) @@ -181,6 +195,9 @@ func (dc *DynCommit) Decode(r io.Reader, _ uint32) error { if val, ok := typeMap[DPMaxHtlcValueInFlightMsat]; ok && val == nil { dc.MaxValueInFlight = fn.Some(MilliSatoshi(maxValueScratch)) } + if val, ok := typeMap[DPHtlcMinimumMsat]; ok && val == nil { + dc.HtlcMinimum = fn.Some(MilliSatoshi(htlcMinScratch)) + } if val, ok := typeMap[DPChannelReserveSatoshis]; ok && val == nil { dc.ChannelReserve = fn.Some(btcutil.Amount(reserveScratch)) } diff --git a/lnwire/dyn_propose.go b/lnwire/dyn_propose.go index 5b200b49245..d25c39e4fed 100644 --- a/lnwire/dyn_propose.go +++ b/lnwire/dyn_propose.go @@ -18,6 +18,10 @@ const ( // record for DynPropose.MaxValueInFlight. DPMaxHtlcValueInFlightMsat tlv.Type = 1 + // DPHtlcMinimumMsat is the TLV type number that identifies the record + // for DynPropose.HtlcMinimum. + DPHtlcMinimumMsat tlv.Type = 7 + // DPChannelReserveSatoshis is the TLV type number that identifies the // for DynPropose.ChannelReserve. DPChannelReserveSatoshis tlv.Type = 2 @@ -50,6 +54,10 @@ type DynPropose struct { // max_htlc_value_in_flight_msat limit of the sender. MaxValueInFlight fn.Option[MilliSatoshi] + // HtlcMinimum, if not nil, proposes a change to the htlc_minimum_msat + // floor of the sender. + HtlcMinimum fn.Option[MilliSatoshi] + // ChannelReserve, if not nil, proposes a change to the // channel_reserve_satoshis requirement of the recipient. ChannelReserve fn.Option[btcutil.Amount] @@ -106,6 +114,14 @@ func (dp *DynPropose) Encode(w *bytes.Buffer, _ uint32) error { ), ) }) + dp.HtlcMinimum.WhenSome(func(min MilliSatoshi) { + protoSats := uint64(min) + tlvRecords = append( + tlvRecords, tlv.MakePrimitiveRecord( + DPHtlcMinimumMsat, &protoSats, + ), + ) + }) dp.ChannelReserve.WhenSome(func(min btcutil.Amount) { channelReserve := uint64(min) tlvRecords = append( @@ -185,6 +201,11 @@ func (dp *DynPropose) Decode(r io.Reader, _ uint32) error { DPMaxHtlcValueInFlightMsat, &maxValueScratch, ) + var htlcMinScratch uint64 + htlcMin := tlv.MakePrimitiveRecord( + DPHtlcMinimumMsat, &htlcMinScratch, + ) + var reserveScratch uint64 reserve := tlv.MakePrimitiveRecord( DPChannelReserveSatoshis, &reserveScratch, @@ -206,7 +227,8 @@ func (dp *DynPropose) Decode(r io.Reader, _ uint32) error { // Create set of Records to read TLV bytestream into. records := []tlv.Record{ - dustLimit, maxValue, reserve, csvDelay, maxHtlcs, chanType, + dustLimit, maxValue, htlcMin, reserve, csvDelay, maxHtlcs, + chanType, } tlv.SortRecords(records) @@ -230,6 +252,9 @@ func (dp *DynPropose) Decode(r io.Reader, _ uint32) error { if val, ok := typeMap[DPMaxHtlcValueInFlightMsat]; ok && val == nil { dp.MaxValueInFlight = fn.Some(MilliSatoshi(maxValueScratch)) } + if val, ok := typeMap[DPHtlcMinimumMsat]; ok && val == nil { + dp.HtlcMinimum = fn.Some(MilliSatoshi(htlcMinScratch)) + } if val, ok := typeMap[DPChannelReserveSatoshis]; ok && val == nil { dp.ChannelReserve = fn.Some(btcutil.Amount(reserveScratch)) } @@ -286,6 +311,14 @@ func (dp *DynPropose) SerializeTlvData() ([]byte, error) { ), ) }) + dp.HtlcMinimum.WhenSome(func(min MilliSatoshi) { + protoSats := uint64(min) + tlvRecords = append( + tlvRecords, tlv.MakePrimitiveRecord( + DPHtlcMinimumMsat, &protoSats, + ), + ) + }) dp.ChannelReserve.WhenSome(func(min btcutil.Amount) { channelReserve := uint64(min) tlvRecords = append( From 79e4e744470b5218c0cd99978ff95de3c6317a1e Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Tue, 15 Oct 2024 20:36:05 -0600 Subject: [PATCH 08/12] lnwire: change DynPropose/DynCommit TLV numbers to align with spec --- lnwire/dyn_propose.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lnwire/dyn_propose.go b/lnwire/dyn_propose.go index d25c39e4fed..8d24e96d0cd 100644 --- a/lnwire/dyn_propose.go +++ b/lnwire/dyn_propose.go @@ -16,27 +16,27 @@ const ( // DPMaxHtlcValueInFlightMsat is the TLV type number that identifies the // record for DynPropose.MaxValueInFlight. - DPMaxHtlcValueInFlightMsat tlv.Type = 1 + DPMaxHtlcValueInFlightMsat tlv.Type = 2 // DPHtlcMinimumMsat is the TLV type number that identifies the record // for DynPropose.HtlcMinimum. - DPHtlcMinimumMsat tlv.Type = 7 + DPHtlcMinimumMsat tlv.Type = 4 // DPChannelReserveSatoshis is the TLV type number that identifies the // for DynPropose.ChannelReserve. - DPChannelReserveSatoshis tlv.Type = 2 + DPChannelReserveSatoshis tlv.Type = 6 // DPToSelfDelay is the TLV type number that identifies the record for // DynPropose.CsvDelay. - DPToSelfDelay tlv.Type = 3 + DPToSelfDelay tlv.Type = 8 // DPMaxAcceptedHtlcs is the TLV type number that identifies the record // for DynPropose.MaxAcceptedHTLCs. - DPMaxAcceptedHtlcs tlv.Type = 4 + DPMaxAcceptedHtlcs tlv.Type = 10 // DPChannelType is the TLV type number that identifies the record for // DynPropose.ChannelType. - DPChannelType tlv.Type = 6 + DPChannelType tlv.Type = 12 ) // DynPropose is a message that is sent during a dynamic commitments negotiation From a72cadf2eda1a118eadea654db28d7f780fbf94a Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Wed, 16 Oct 2024 18:21:00 -0600 Subject: [PATCH 09/12] lnwire: convert DynPropose and DynCommit to use typed tlv records --- lnwire/dyn_commit.go | 176 ++++++---------------- lnwire/dyn_propose.go | 333 +++++++++++++---------------------------- lnwire/test_message.go | 33 ++-- 3 files changed, 166 insertions(+), 376 deletions(-) diff --git a/lnwire/dyn_commit.go b/lnwire/dyn_commit.go index f65020371f4..73b992f6175 100644 --- a/lnwire/dyn_commit.go +++ b/lnwire/dyn_commit.go @@ -5,7 +5,6 @@ import ( "io" "github.com/btcsuite/btcd/btcutil" - "github.com/lightningnetwork/lnd/fn/v2" "github.com/lightningnetwork/lnd/tlv" ) @@ -43,75 +42,12 @@ func (dc *DynCommit) Encode(w *bytes.Buffer, _ uint32) error { return err } - var tlvRecords []tlv.Record - dc.DustLimit.WhenSome(func(dl btcutil.Amount) { - protoSats := uint64(dl) - tlvRecords = append( - tlvRecords, tlv.MakePrimitiveRecord( - DPDustLimitSatoshis, &protoSats, - ), - ) - }) - dc.MaxValueInFlight.WhenSome(func(max MilliSatoshi) { - protoSats := uint64(max) - tlvRecords = append( - tlvRecords, tlv.MakePrimitiveRecord( - DPMaxHtlcValueInFlightMsat, &protoSats, - ), - ) - }) - dc.HtlcMinimum.WhenSome(func(min MilliSatoshi) { - protoSats := uint64(min) - tlvRecords = append( - tlvRecords, tlv.MakePrimitiveRecord( - DPHtlcMinimumMsat, &protoSats, - ), - ) - }) - dc.ChannelReserve.WhenSome(func(min btcutil.Amount) { - channelReserve := uint64(min) - tlvRecords = append( - tlvRecords, tlv.MakePrimitiveRecord( - DPChannelReserveSatoshis, &channelReserve, - ), - ) - }) - dc.CsvDelay.WhenSome(func(wait uint16) { - tlvRecords = append( - tlvRecords, tlv.MakePrimitiveRecord( - DPToSelfDelay, &wait, - ), - ) - }) - dc.MaxAcceptedHTLCs.WhenSome(func(max uint16) { - tlvRecords = append( - tlvRecords, tlv.MakePrimitiveRecord( - DPMaxAcceptedHtlcs, &max, - ), - ) - }) - dc.ChannelType.WhenSome(func(ty ChannelType) { - tlvRecords = append( - tlvRecords, tlv.MakeDynamicRecord( - DPChannelType, &ty, - ty.featureBitLen, - channelTypeEncoder, channelTypeDecoder, - ), - ) - }) - tlv.SortRecords(tlvRecords) - - tlvStream, err := tlv.NewStream(tlvRecords...) + var extra ExtraOpaqueData + err := extra.PackRecords(dynProposeRecords(&dc.DynPropose)...) if err != nil { return err } - - var extraBytesWriter bytes.Buffer - if err := tlvStream.Encode(&extraBytesWriter); err != nil { - return err - } - - dc.ExtraData = ExtraOpaqueData(extraBytesWriter.Bytes()) + dc.ExtraData = extra return WriteBytes(w, dc.ExtraData) } @@ -135,80 +71,52 @@ func (dc *DynCommit) Decode(r io.Reader, _ uint32) error { } // Prepare receiving buffers to be filled by TLV extraction. - var dustLimitScratch uint64 - dustLimit := tlv.MakePrimitiveRecord( - DPDustLimitSatoshis, &dustLimitScratch, - ) - - var maxValueScratch uint64 - maxValue := tlv.MakePrimitiveRecord( - DPMaxHtlcValueInFlightMsat, &maxValueScratch, - ) - - var htlcMinScratch uint64 - htlcMin := tlv.MakePrimitiveRecord( - DPHtlcMinimumMsat, &htlcMinScratch, - ) - - var reserveScratch uint64 - reserve := tlv.MakePrimitiveRecord( - DPChannelReserveSatoshis, &reserveScratch, + var dustLimit tlv.RecordT[tlv.TlvType0, uint64] + var maxValue tlv.RecordT[tlv.TlvType2, uint64] + var htlcMin tlv.RecordT[tlv.TlvType4, uint64] + var reserve tlv.RecordT[tlv.TlvType6, uint64] + csvDelay := dc.CsvDelay.Zero() + maxHtlcs := dc.MaxAcceptedHTLCs.Zero() + chanType := dc.ChannelType.Zero() + + typeMap, err := tlvRecords.ExtractRecords( + &dustLimit, &maxValue, &htlcMin, &reserve, &csvDelay, &maxHtlcs, + &chanType, ) - - var csvDelayScratch uint16 - csvDelay := tlv.MakePrimitiveRecord(DPToSelfDelay, &csvDelayScratch) - - var maxHtlcsScratch uint16 - maxHtlcs := tlv.MakePrimitiveRecord( - DPMaxAcceptedHtlcs, &maxHtlcsScratch, - ) - - var chanTypeScratch ChannelType - chanType := tlv.MakeDynamicRecord( - DPChannelType, &chanTypeScratch, chanTypeScratch.featureBitLen, - channelTypeEncoder, channelTypeDecoder, - ) - - // Create set of Records to read TLV bytestream into. - records := []tlv.Record{ - dustLimit, maxValue, htlcMin, reserve, csvDelay, maxHtlcs, - chanType, - } - tlv.SortRecords(records) - - // Read TLV stream into record set. - extraBytesReader := bytes.NewReader(tlvRecords) - tlvStream, err := tlv.NewStream(records...) - if err != nil { - return err - } - typeMap, err := tlvStream.DecodeWithParsedTypesP2P(extraBytesReader) if err != nil { return err } // Check the results of the TLV Stream decoding and appropriately set // message fields. - if val, ok := typeMap[DPDustLimitSatoshis]; ok && val == nil { - dc.DustLimit = fn.Some(btcutil.Amount(dustLimitScratch)) - } - if val, ok := typeMap[DPMaxHtlcValueInFlightMsat]; ok && val == nil { - dc.MaxValueInFlight = fn.Some(MilliSatoshi(maxValueScratch)) - } - if val, ok := typeMap[DPHtlcMinimumMsat]; ok && val == nil { - dc.HtlcMinimum = fn.Some(MilliSatoshi(htlcMinScratch)) - } - if val, ok := typeMap[DPChannelReserveSatoshis]; ok && val == nil { - dc.ChannelReserve = fn.Some(btcutil.Amount(reserveScratch)) - } - if val, ok := typeMap[DPToSelfDelay]; ok && val == nil { - dc.CsvDelay = fn.Some(csvDelayScratch) - } - if val, ok := typeMap[DPMaxAcceptedHtlcs]; ok && val == nil { - dc.MaxAcceptedHTLCs = fn.Some(maxHtlcsScratch) - } - if val, ok := typeMap[DPChannelType]; ok && val == nil { - dc.ChannelType = fn.Some(chanTypeScratch) + if val, ok := typeMap[dc.DustLimit.TlvType()]; ok && val == nil { + var rec tlv.RecordT[tlv.TlvType0, btcutil.Amount] + rec.Val = btcutil.Amount(dustLimit.Val) + dc.DustLimit = tlv.SomeRecordT(rec) + } + if val, ok := typeMap[dc.MaxValueInFlight.TlvType()]; ok && val == nil { + var rec tlv.RecordT[tlv.TlvType2, MilliSatoshi] + rec.Val = MilliSatoshi(maxValue.Val) + dc.MaxValueInFlight = tlv.SomeRecordT(rec) + } + if val, ok := typeMap[dc.HtlcMinimum.TlvType()]; ok && val == nil { + var rec tlv.RecordT[tlv.TlvType4, MilliSatoshi] + rec.Val = MilliSatoshi(htlcMin.Val) + dc.HtlcMinimum = tlv.SomeRecordT(rec) + } + if val, ok := typeMap[dc.ChannelReserve.TlvType()]; ok && val == nil { + var rec tlv.RecordT[tlv.TlvType6, btcutil.Amount] + rec.Val = btcutil.Amount(reserve.Val) + dc.ChannelReserve = tlv.SomeRecordT(rec) + } + if val, ok := typeMap[dc.CsvDelay.TlvType()]; ok && val == nil { + dc.CsvDelay = tlv.SomeRecordT(csvDelay) + } + if val, ok := typeMap[dc.MaxAcceptedHTLCs.TlvType()]; ok && val == nil { + dc.MaxAcceptedHTLCs = tlv.SomeRecordT(maxHtlcs) + } + if val, ok := typeMap[dc.ChannelType.TlvType()]; ok && val == nil { + dc.ChannelType = tlv.SomeRecordT(chanType) } if len(tlvRecords) != 0 { diff --git a/lnwire/dyn_propose.go b/lnwire/dyn_propose.go index 8d24e96d0cd..c1de59ef6e5 100644 --- a/lnwire/dyn_propose.go +++ b/lnwire/dyn_propose.go @@ -5,40 +5,9 @@ import ( "io" "github.com/btcsuite/btcd/btcutil" - "github.com/lightningnetwork/lnd/fn/v2" "github.com/lightningnetwork/lnd/tlv" ) -const ( - // DPDustLimitSatoshis is the TLV type number that identifies the record - // for DynPropose.DustLimit. - DPDustLimitSatoshis tlv.Type = 0 - - // DPMaxHtlcValueInFlightMsat is the TLV type number that identifies the - // record for DynPropose.MaxValueInFlight. - DPMaxHtlcValueInFlightMsat tlv.Type = 2 - - // DPHtlcMinimumMsat is the TLV type number that identifies the record - // for DynPropose.HtlcMinimum. - DPHtlcMinimumMsat tlv.Type = 4 - - // DPChannelReserveSatoshis is the TLV type number that identifies the - // for DynPropose.ChannelReserve. - DPChannelReserveSatoshis tlv.Type = 6 - - // DPToSelfDelay is the TLV type number that identifies the record for - // DynPropose.CsvDelay. - DPToSelfDelay tlv.Type = 8 - - // DPMaxAcceptedHtlcs is the TLV type number that identifies the record - // for DynPropose.MaxAcceptedHTLCs. - DPMaxAcceptedHtlcs tlv.Type = 10 - - // DPChannelType is the TLV type number that identifies the record for - // DynPropose.ChannelType. - DPChannelType tlv.Type = 12 -) - // DynPropose is a message that is sent during a dynamic commitments negotiation // process. It is sent by both parties to propose new channel parameters. type DynPropose struct { @@ -48,31 +17,31 @@ type DynPropose struct { // DustLimit, if not nil, proposes a change to the dust_limit_satoshis // for the sender's commitment transaction. - DustLimit fn.Option[btcutil.Amount] + DustLimit tlv.OptionalRecordT[tlv.TlvType0, btcutil.Amount] // MaxValueInFlight, if not nil, proposes a change to the // max_htlc_value_in_flight_msat limit of the sender. - MaxValueInFlight fn.Option[MilliSatoshi] + MaxValueInFlight tlv.OptionalRecordT[tlv.TlvType2, MilliSatoshi] // HtlcMinimum, if not nil, proposes a change to the htlc_minimum_msat // floor of the sender. - HtlcMinimum fn.Option[MilliSatoshi] + HtlcMinimum tlv.OptionalRecordT[tlv.TlvType4, MilliSatoshi] // ChannelReserve, if not nil, proposes a change to the // channel_reserve_satoshis requirement of the recipient. - ChannelReserve fn.Option[btcutil.Amount] + ChannelReserve tlv.OptionalRecordT[tlv.TlvType6, btcutil.Amount] // CsvDelay, if not nil, proposes a change to the to_self_delay // requirement of the recipient. - CsvDelay fn.Option[uint16] + CsvDelay tlv.OptionalRecordT[tlv.TlvType8, uint16] // MaxAcceptedHTLCs, if not nil, proposes a change to the // max_accepted_htlcs limit of the sender. - MaxAcceptedHTLCs fn.Option[uint16] + MaxAcceptedHTLCs tlv.OptionalRecordT[tlv.TlvType10, uint16] // ChannelType, if not nil, proposes a change to the channel_type // parameter. - ChannelType fn.Option[ChannelType] + ChannelType tlv.OptionalRecordT[tlv.TlvType12, ChannelType] // ExtraData is the set of data that was appended to this message to // fill out the full maximum transport message size. These fields can @@ -97,76 +66,14 @@ var _ SizeableMessage = (*DynPropose)(nil) // // This is a part of the lnwire.Message interface. func (dp *DynPropose) Encode(w *bytes.Buffer, _ uint32) error { - var tlvRecords []tlv.Record - dp.DustLimit.WhenSome(func(dl btcutil.Amount) { - protoSats := uint64(dl) - tlvRecords = append( - tlvRecords, tlv.MakePrimitiveRecord( - DPDustLimitSatoshis, &protoSats, - ), - ) - }) - dp.MaxValueInFlight.WhenSome(func(max MilliSatoshi) { - protoSats := uint64(max) - tlvRecords = append( - tlvRecords, tlv.MakePrimitiveRecord( - DPMaxHtlcValueInFlightMsat, &protoSats, - ), - ) - }) - dp.HtlcMinimum.WhenSome(func(min MilliSatoshi) { - protoSats := uint64(min) - tlvRecords = append( - tlvRecords, tlv.MakePrimitiveRecord( - DPHtlcMinimumMsat, &protoSats, - ), - ) - }) - dp.ChannelReserve.WhenSome(func(min btcutil.Amount) { - channelReserve := uint64(min) - tlvRecords = append( - tlvRecords, tlv.MakePrimitiveRecord( - DPChannelReserveSatoshis, &channelReserve, - ), - ) - }) - dp.CsvDelay.WhenSome(func(wait uint16) { - tlvRecords = append( - tlvRecords, tlv.MakePrimitiveRecord( - DPToSelfDelay, &wait, - ), - ) - }) - dp.MaxAcceptedHTLCs.WhenSome(func(max uint16) { - tlvRecords = append( - tlvRecords, tlv.MakePrimitiveRecord( - DPMaxAcceptedHtlcs, &max, - ), - ) - }) - dp.ChannelType.WhenSome(func(ty ChannelType) { - tlvRecords = append( - tlvRecords, tlv.MakeDynamicRecord( - DPChannelType, &ty, - ty.featureBitLen, - channelTypeEncoder, channelTypeDecoder, - ), - ) - }) - tlv.SortRecords(tlvRecords) - - tlvStream, err := tlv.NewStream(tlvRecords...) - if err != nil { + if err := WriteChannelID(w, dp.ChanID); err != nil { return err } - var extraBytesWriter bytes.Buffer - if err := tlvStream.Encode(&extraBytesWriter); err != nil { - return err - } - dp.ExtraData = ExtraOpaqueData(extraBytesWriter.Bytes()) + producers := dynProposeRecords(dp) - if err := WriteChannelID(w, dp.ChanID); err != nil { + err := EncodeMessageExtraData(&dp.ExtraData, producers...) + if err != nil { return err } @@ -191,81 +98,52 @@ func (dp *DynPropose) Decode(r io.Reader, _ uint32) error { } // Prepare receiving buffers to be filled by TLV extraction. - var dustLimitScratch uint64 - dustLimit := tlv.MakePrimitiveRecord( - DPDustLimitSatoshis, &dustLimitScratch, - ) - - var maxValueScratch uint64 - maxValue := tlv.MakePrimitiveRecord( - DPMaxHtlcValueInFlightMsat, &maxValueScratch, - ) - - var htlcMinScratch uint64 - htlcMin := tlv.MakePrimitiveRecord( - DPHtlcMinimumMsat, &htlcMinScratch, - ) - - var reserveScratch uint64 - reserve := tlv.MakePrimitiveRecord( - DPChannelReserveSatoshis, &reserveScratch, - ) - - var csvDelayScratch uint16 - csvDelay := tlv.MakePrimitiveRecord(DPToSelfDelay, &csvDelayScratch) - - var maxHtlcsScratch uint16 - maxHtlcs := tlv.MakePrimitiveRecord( - DPMaxAcceptedHtlcs, &maxHtlcsScratch, + var dustLimit tlv.RecordT[tlv.TlvType0, uint64] + var maxValue tlv.RecordT[tlv.TlvType2, uint64] + var htlcMin tlv.RecordT[tlv.TlvType4, uint64] + var reserve tlv.RecordT[tlv.TlvType6, uint64] + csvDelay := dp.CsvDelay.Zero() + maxHtlcs := dp.MaxAcceptedHTLCs.Zero() + chanType := dp.ChannelType.Zero() + + typeMap, err := tlvRecords.ExtractRecords( + &dustLimit, &maxValue, &htlcMin, &reserve, &csvDelay, &maxHtlcs, + &chanType, ) - - var chanTypeScratch ChannelType - chanType := tlv.MakeDynamicRecord( - DPChannelType, &chanTypeScratch, chanTypeScratch.featureBitLen, - channelTypeEncoder, channelTypeDecoder, - ) - - // Create set of Records to read TLV bytestream into. - records := []tlv.Record{ - dustLimit, maxValue, htlcMin, reserve, csvDelay, maxHtlcs, - chanType, - } - tlv.SortRecords(records) - - // Read TLV stream into record set. - extraBytesReader := bytes.NewReader(tlvRecords) - tlvStream, err := tlv.NewStream(records...) - if err != nil { - return err - } - - typeMap, err := tlvStream.DecodeWithParsedTypesP2P(extraBytesReader) if err != nil { return err } // Check the results of the TLV Stream decoding and appropriately set // message fields. - if val, ok := typeMap[DPDustLimitSatoshis]; ok && val == nil { - dp.DustLimit = fn.Some(btcutil.Amount(dustLimitScratch)) + if val, ok := typeMap[dp.DustLimit.TlvType()]; ok && val == nil { + var rec tlv.RecordT[tlv.TlvType0, btcutil.Amount] + rec.Val = btcutil.Amount(dustLimit.Val) + dp.DustLimit = tlv.SomeRecordT(rec) } - if val, ok := typeMap[DPMaxHtlcValueInFlightMsat]; ok && val == nil { - dp.MaxValueInFlight = fn.Some(MilliSatoshi(maxValueScratch)) + 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) } - if val, ok := typeMap[DPHtlcMinimumMsat]; ok && val == nil { - dp.HtlcMinimum = fn.Some(MilliSatoshi(htlcMinScratch)) + 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) } - if val, ok := typeMap[DPChannelReserveSatoshis]; ok && val == nil { - dp.ChannelReserve = fn.Some(btcutil.Amount(reserveScratch)) + if val, ok := typeMap[dp.ChannelReserve.TlvType()]; ok && val == nil { + var rec tlv.RecordT[tlv.TlvType6, btcutil.Amount] + rec.Val = btcutil.Amount(reserve.Val) + dp.ChannelReserve = tlv.SomeRecordT(rec) } - if val, ok := typeMap[DPToSelfDelay]; ok && val == nil { - dp.CsvDelay = fn.Some(csvDelayScratch) + if val, ok := typeMap[dp.CsvDelay.TlvType()]; ok && val == nil { + dp.CsvDelay = tlv.SomeRecordT(csvDelay) } - if val, ok := typeMap[DPMaxAcceptedHtlcs]; ok && val == nil { - dp.MaxAcceptedHTLCs = fn.Some(maxHtlcsScratch) + if val, ok := typeMap[dp.MaxAcceptedHTLCs.TlvType()]; ok && val == nil { + dp.MaxAcceptedHTLCs = tlv.SomeRecordT(maxHtlcs) } - if val, ok := typeMap[DPChannelType]; ok && val == nil { - dp.ChannelType = fn.Some(chanTypeScratch) + if val, ok := typeMap[dp.ChannelType.TlvType()]; ok && val == nil { + dp.ChannelType = tlv.SomeRecordT(chanType) } if len(tlvRecords) != 0 { @@ -294,74 +172,67 @@ func (dp *DynPropose) SerializedSize() (uint32, error) { // the parameters on deck for changing) and serializes just this component. The // main purpose of this is to make it easier to validate the DynAck signature. func (dp *DynPropose) SerializeTlvData() ([]byte, error) { - var tlvRecords []tlv.Record - dp.DustLimit.WhenSome(func(dl btcutil.Amount) { - protoSats := uint64(dl) - tlvRecords = append( - tlvRecords, tlv.MakePrimitiveRecord( - DPDustLimitSatoshis, &protoSats, - ), - ) - }) - dp.MaxValueInFlight.WhenSome(func(max MilliSatoshi) { - protoSats := uint64(max) - tlvRecords = append( - tlvRecords, tlv.MakePrimitiveRecord( - DPMaxHtlcValueInFlightMsat, &protoSats, - ), - ) - }) - dp.HtlcMinimum.WhenSome(func(min MilliSatoshi) { - protoSats := uint64(min) - tlvRecords = append( - tlvRecords, tlv.MakePrimitiveRecord( - DPHtlcMinimumMsat, &protoSats, - ), - ) - }) - dp.ChannelReserve.WhenSome(func(min btcutil.Amount) { - channelReserve := uint64(min) - tlvRecords = append( - tlvRecords, tlv.MakePrimitiveRecord( - DPChannelReserveSatoshis, &channelReserve, - ), - ) - }) - dp.CsvDelay.WhenSome(func(wait uint16) { - tlvRecords = append( - tlvRecords, tlv.MakePrimitiveRecord( - DPToSelfDelay, &wait, - ), - ) - }) - dp.MaxAcceptedHTLCs.WhenSome(func(max uint16) { - tlvRecords = append( - tlvRecords, tlv.MakePrimitiveRecord( - DPMaxAcceptedHtlcs, &max, - ), - ) - }) - dp.ChannelType.WhenSome(func(ty ChannelType) { - tlvRecords = append( - tlvRecords, tlv.MakeDynamicRecord( - DPChannelType, &ty, - ty.featureBitLen, - channelTypeEncoder, channelTypeDecoder, - ), - ) - }) - tlv.SortRecords(tlvRecords) - - tlvStream, err := tlv.NewStream(tlvRecords...) - if err != nil { - return nil, err - } + producers := dynProposeRecords(dp) - var outBuf bytes.Buffer - err = tlvStream.Encode(&outBuf) + var extra ExtraOpaqueData + err := extra.PackRecords(producers...) if err != nil { return nil, err } - return outBuf.Bytes(), nil + return extra, nil +} + +func dynProposeRecords(dp *DynPropose) []tlv.RecordProducer { + recordProducers := make([]tlv.RecordProducer, 0, 7) + + dp.DustLimit.WhenSome( + func(dl tlv.RecordT[tlv.TlvType0, btcutil.Amount]) { + rec := tlv.NewPrimitiveRecord[tlv.TlvType0]( + uint64(dl.Val), + ) + recordProducers = append(recordProducers, &rec) + }, + ) + dp.MaxValueInFlight.WhenSome( + func(max tlv.RecordT[tlv.TlvType2, MilliSatoshi]) { + rec := tlv.NewPrimitiveRecord[tlv.TlvType2]( + uint64(max.Val), + ) + recordProducers = append(recordProducers, &rec) + }, + ) + dp.HtlcMinimum.WhenSome( + func(min tlv.RecordT[tlv.TlvType4, MilliSatoshi]) { + rec := tlv.NewPrimitiveRecord[tlv.TlvType4]( + uint64(min.Val), + ) + recordProducers = append(recordProducers, &rec) + }, + ) + dp.ChannelReserve.WhenSome( + func(reserve tlv.RecordT[tlv.TlvType6, btcutil.Amount]) { + rec := tlv.NewPrimitiveRecord[tlv.TlvType6]( + uint64(reserve.Val), + ) + recordProducers = append(recordProducers, &rec) + }, + ) + dp.CsvDelay.WhenSome( + func(wait tlv.RecordT[tlv.TlvType8, uint16]) { + recordProducers = append(recordProducers, &wait) + }, + ) + dp.MaxAcceptedHTLCs.WhenSome( + func(max tlv.RecordT[tlv.TlvType10, uint16]) { + recordProducers = append(recordProducers, &max) + }, + ) + dp.ChannelType.WhenSome( + func(ty tlv.RecordT[tlv.TlvType12, ChannelType]) { + recordProducers = append(recordProducers, &ty) + }, + ) + + return recordProducers } diff --git a/lnwire/test_message.go b/lnwire/test_message.go index 4cf9bb0cdde..b29fa67b6a7 100644 --- a/lnwire/test_message.go +++ b/lnwire/test_message.go @@ -833,32 +833,43 @@ func (dp *DynPropose) RandTestMessage(t *rapid.T) Message { // Generate random values for each included field if includeDustLimit { - dl := btcutil.Amount(rapid.Uint32().Draw(t, "dustLimit")) - msg.DustLimit = fn.Some(dl) + var rec tlv.RecordT[tlv.TlvType0, btcutil.Amount] + val := btcutil.Amount(rapid.Uint32().Draw(t, "dustLimit")) + rec.Val = val + msg.DustLimit = tlv.SomeRecordT(rec) } if includeMaxValueInFlight { - mvif := MilliSatoshi(rapid.Uint64().Draw(t, "maxValueInFlight")) - msg.MaxValueInFlight = fn.Some(mvif) + var rec tlv.RecordT[tlv.TlvType2, MilliSatoshi] + val := MilliSatoshi(rapid.Uint64().Draw(t, "maxValueInFlight")) + rec.Val = val + msg.MaxValueInFlight = tlv.SomeRecordT(rec) } if includeChannelReserve { - cr := btcutil.Amount(rapid.Uint32().Draw(t, "channelReserve")) - msg.ChannelReserve = fn.Some(cr) + var rec tlv.RecordT[tlv.TlvType6, btcutil.Amount] + val := btcutil.Amount(rapid.Uint32().Draw(t, "channelReserve")) + rec.Val = val + msg.ChannelReserve = tlv.SomeRecordT(rec) } if includeCsvDelay { - cd := rapid.Uint16().Draw(t, "csvDelay") - msg.CsvDelay = fn.Some(cd) + csvDelay := msg.CsvDelay.Zero() + val := rapid.Uint16().Draw(t, "csvDelay") + csvDelay.Val = val + msg.CsvDelay = tlv.SomeRecordT(csvDelay) } if includeMaxAcceptedHTLCs { - mah := rapid.Uint16().Draw(t, "maxAcceptedHTLCs") - msg.MaxAcceptedHTLCs = fn.Some(mah) + maxHtlcs := msg.MaxAcceptedHTLCs.Zero() + maxHtlcs.Val = rapid.Uint16().Draw(t, "maxAcceptedHTLCs") + msg.MaxAcceptedHTLCs = tlv.SomeRecordT(maxHtlcs) } if includeChannelType { - msg.ChannelType = fn.Some(*RandChannelType(t)) + chanType := msg.ChannelType.Zero() + chanType.Val = *RandChannelType(t) + msg.ChannelType = tlv.SomeRecordT(chanType) } return msg From 8456aef9eb0149c57f75b996ec9f4d44c6f680a1 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Wed, 25 Jun 2025 02:25:47 +0800 Subject: [PATCH 10/12] gitignore: ignore test data from rapid --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 1e498b0cf28..11c67fe65c4 100644 --- a/.gitignore +++ b/.gitignore @@ -82,3 +82,6 @@ coverage.txt /lnd-*/ .aider* + +# All test data generated from rapid. +*/testdata From 828486e35a88773d32613095b5ccac8c8f9f93f9 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Wed, 25 Jun 2025 01:56:34 +0800 Subject: [PATCH 11/12] lnwire: fix unit test for `DynCommit` --- lnwire/dyn_commit.go | 13 ++++++- lnwire/test_message.go | 85 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 1 deletion(-) diff --git a/lnwire/dyn_commit.go b/lnwire/dyn_commit.go index 73b992f6175..083da162609 100644 --- a/lnwire/dyn_commit.go +++ b/lnwire/dyn_commit.go @@ -25,10 +25,14 @@ type DynCommit struct { ExtraData ExtraOpaqueData } -// A compile time check to ensure DynAck implements the lnwire.Message +// A compile time check to ensure DynCommit implements the lnwire.Message // interface. var _ Message = (*DynCommit)(nil) +// A compile time check to ensure DynCommit implements the +// lnwire.SizeableMessage interface. +var _ SizeableMessage = (*DynCommit)(nil) + // Encode serializes the target DynAck into the passed io.Writer. Serialization // will observe the rules defined by the passed protocol version. // @@ -133,3 +137,10 @@ func (dc *DynCommit) Decode(r io.Reader, _ uint32) error { func (dc *DynCommit) MsgType() MessageType { return MsgDynCommit } + +// SerializedSize returns the serialized size of the message in bytes. +// +// This is part of the lnwire.SizeableMessage interface. +func (dc *DynCommit) SerializedSize() (uint32, error) { + return MessageSerializedSize(dc) +} diff --git a/lnwire/test_message.go b/lnwire/test_message.go index b29fa67b6a7..ec04ae16364 100644 --- a/lnwire/test_message.go +++ b/lnwire/test_message.go @@ -909,6 +909,91 @@ func (dr *DynReject) RandTestMessage(t *rapid.T) Message { } } +// A compile time check to ensure DynCommit implements the lnwire.TestMessage +// interface. +var _ TestMessage = (*DynCommit)(nil) + +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (dc *DynCommit) RandTestMessage(t *rapid.T) Message { + chanID := RandChannelID(t) + + da := &DynAck{ + ChanID: chanID, + } + + dp := &DynPropose{ + ChanID: chanID, + } + + // Randomly decide which optional fields to include + includeDustLimit := rapid.Bool().Draw(t, "includeDustLimit") + includeMaxValueInFlight := rapid.Bool().Draw( + t, "includeMaxValueInFlight", + ) + includeChannelReserve := rapid.Bool().Draw(t, "includeChannelReserve") + includeCsvDelay := rapid.Bool().Draw(t, "includeCsvDelay") + includeMaxAcceptedHTLCs := rapid.Bool().Draw( + t, "includeMaxAcceptedHTLCs", + ) + includeChannelType := rapid.Bool().Draw(t, "includeChannelType") + + // Generate random values for each included field + if includeDustLimit { + var rec tlv.RecordT[tlv.TlvType0, btcutil.Amount] + val := btcutil.Amount(rapid.Uint32().Draw(t, "dustLimit")) + rec.Val = val + dp.DustLimit = tlv.SomeRecordT(rec) + } + + if includeMaxValueInFlight { + var rec tlv.RecordT[tlv.TlvType2, MilliSatoshi] + val := MilliSatoshi(rapid.Uint64().Draw(t, "maxValueInFlight")) + rec.Val = val + dp.MaxValueInFlight = tlv.SomeRecordT(rec) + } + + if includeChannelReserve { + var rec tlv.RecordT[tlv.TlvType6, btcutil.Amount] + val := btcutil.Amount(rapid.Uint32().Draw(t, "channelReserve")) + rec.Val = val + dp.ChannelReserve = tlv.SomeRecordT(rec) + } + + if includeCsvDelay { + csvDelay := dp.CsvDelay.Zero() + val := rapid.Uint16().Draw(t, "csvDelay") + csvDelay.Val = val + dp.CsvDelay = tlv.SomeRecordT(csvDelay) + } + + if includeMaxAcceptedHTLCs { + maxHtlcs := dp.MaxAcceptedHTLCs.Zero() + maxHtlcs.Val = rapid.Uint16().Draw(t, "maxAcceptedHTLCs") + dp.MaxAcceptedHTLCs = tlv.SomeRecordT(maxHtlcs) + } + + if includeChannelType { + chanType := dp.ChannelType.Zero() + chanType.Val = *RandChannelType(t) + dp.ChannelType = tlv.SomeRecordT(chanType) + } + + var extraData ExtraOpaqueData + randData := RandExtraOpaqueData(t, nil) + if len(randData) > 0 { + extraData = randData + } + + return &DynCommit{ + DynPropose: *dp, + DynAck: *da, + ExtraData: extraData, + } +} + // A compile time check to ensure FundingCreated implements the TestMessage // interface. var _ TestMessage = (*FundingCreated)(nil) From c64e3a6c349448348fb24e25260e6cb31dcb2cc3 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Wed, 25 Jun 2025 03:59:53 +0800 Subject: [PATCH 12/12] lnwire: fix linter --- lnwire/dyn_propose.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lnwire/dyn_propose.go b/lnwire/dyn_propose.go index c1de59ef6e5..21a7ce524b7 100644 --- a/lnwire/dyn_propose.go +++ b/lnwire/dyn_propose.go @@ -195,17 +195,17 @@ func dynProposeRecords(dp *DynPropose) []tlv.RecordProducer { }, ) dp.MaxValueInFlight.WhenSome( - func(max tlv.RecordT[tlv.TlvType2, MilliSatoshi]) { + func(mvif tlv.RecordT[tlv.TlvType2, MilliSatoshi]) { rec := tlv.NewPrimitiveRecord[tlv.TlvType2]( - uint64(max.Val), + uint64(mvif.Val), ) recordProducers = append(recordProducers, &rec) }, ) dp.HtlcMinimum.WhenSome( - func(min tlv.RecordT[tlv.TlvType4, MilliSatoshi]) { + func(hm tlv.RecordT[tlv.TlvType4, MilliSatoshi]) { rec := tlv.NewPrimitiveRecord[tlv.TlvType4]( - uint64(min.Val), + uint64(hm.Val), ) recordProducers = append(recordProducers, &rec) }, @@ -224,8 +224,8 @@ func dynProposeRecords(dp *DynPropose) []tlv.RecordProducer { }, ) dp.MaxAcceptedHTLCs.WhenSome( - func(max tlv.RecordT[tlv.TlvType10, uint16]) { - recordProducers = append(recordProducers, &max) + func(mah tlv.RecordT[tlv.TlvType10, uint16]) { + recordProducers = append(recordProducers, &mah) }, ) dp.ChannelType.WhenSome(