From f3943fb530a7edb5cb9aa57d24b0ee5508b92c2d Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Fri, 13 Sep 2024 16:27:59 -0700 Subject: [PATCH 1/9] lnwire: remove no longer used initiator field --- lnwire/dyn_propose.go | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/lnwire/dyn_propose.go b/lnwire/dyn_propose.go index b0cc1198e9..4744e89fd3 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] @@ -191,10 +185,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) } @@ -205,7 +195,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 } From cd8ea086e6bd9233e3b3a014163328f2cc7b2d33 Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Thu, 12 Sep 2024 14:52:09 -0700 Subject: [PATCH 2/9] 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 24f23a228d..b3c37da75a 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 @@ -50,6 +54,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( @@ -84,7 +92,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 203f4db0aa6df2652f2ec31c339a9d23a737e004 Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Thu, 12 Sep 2024 17:24:54 -0700 Subject: [PATCH 3/9] lnwire: add DynCommit message to match spec --- lnwire/dyn_commit.go | 247 ++++++++++++++++++++++++++++++++++++++++++ lnwire/fuzz_test.go | 6 + lnwire/lnwire_test.go | 55 ++++++++++ lnwire/message.go | 5 + 4 files changed, 313 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 0000000000..5684473b3c --- /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" + "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 e608eb9b0b..054af585cf 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/lnwire_test.go b/lnwire/lnwire_test.go index 6b9630f58a..4eff6c47bd 100644 --- a/lnwire/lnwire_test.go +++ b/lnwire/lnwire_test.go @@ -925,6 +925,55 @@ func TestLightningWireProtocol(t *testing.T) { v[0] = reflect.ValueOf(da) }, + MsgDynCommit: func(v []reflect.Value, r *rand.Rand) { + var dc DynCommit + + rand.Read(dc.DynPropose.ChanID[:]) + copy(dc.DynAck.ChanID[:], dc.DynPropose.ChanID[:]) + + rand.Read(dc.Sig.bytes[:]) + if rand.Uint32()%2 == 0 { + v := btcutil.Amount(rand.Uint32()) + dc.DustLimit = fn.Some(v) + } + + if rand.Uint32()%2 == 0 { + v := MilliSatoshi(rand.Uint32()) + dc.MaxValueInFlight = fn.Some(v) + } + + if rand.Uint32()%2 == 0 { + v := btcutil.Amount(rand.Uint32()) + dc.ChannelReserve = fn.Some(v) + } + + if rand.Uint32()%2 == 0 { + v := uint16(rand.Uint32()) + dc.CsvDelay = fn.Some(v) + } + + if rand.Uint32()%2 == 0 { + v := uint16(rand.Uint32()) + dc.MaxAcceptedHTLCs = fn.Some(v) + } + + if rand.Uint32()%2 == 0 { + v, _ := btcec.NewPrivateKey() + dc.FundingKey = fn.Some(*v.PubKey()) + } + + if rand.Uint32()%2 == 0 { + v := ChannelType(*NewRawFeatureVector()) + dc.ChannelType = fn.Some(v) + } + + if rand.Uint32()%2 == 0 { + v := chainfee.SatPerKWeight(rand.Uint32()) + dc.KickoffFeerate = fn.Some(v) + } + + v[0] = reflect.ValueOf(dc) + }, MsgKickoffSig: func(v []reflect.Value, r *rand.Rand) { ks := KickoffSig{ ExtraData: make([]byte, 0), @@ -1779,6 +1828,12 @@ func TestLightningWireProtocol(t *testing.T) { return mainScenario(&m) }, }, + { + msgType: MsgDynCommit, + scenario: func(m DynCommit) bool { + return mainScenario(&m) + }, + }, { msgType: MsgKickoffSig, scenario: func(m KickoffSig) bool { diff --git a/lnwire/message.go b/lnwire/message.go index 68b09692e5..34effc8515 100644 --- a/lnwire/message.go +++ b/lnwire/message.go @@ -40,6 +40,7 @@ const ( MsgDynPropose = 111 MsgDynAck = 113 MsgDynReject = 115 + MsgDynCommit = 117 MsgUpdateAddHTLC = 128 MsgUpdateFulfillHTLC = 130 MsgUpdateFailHTLC = 131 @@ -131,6 +132,8 @@ func (t MessageType) String() string { return "DynAck" case MsgDynReject: return "DynReject" + case MsgDynCommit: + return "DynCommit" case MsgKickoffSig: return "KickoffSig" case MsgUpdateAddHTLC: @@ -266,6 +269,8 @@ func makeEmptyMessage(msgType MessageType) (Message, error) { msg = &DynAck{} case MsgDynReject: msg = &DynReject{} + case MsgDynCommit: + msg = &DynCommit{} case MsgKickoffSig: msg = &KickoffSig{} case MsgUpdateAddHTLC: From d9ff9086c6cdfdcf196135c3766d2ee6b4c7458f Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Fri, 13 Sep 2024 16:25:19 -0700 Subject: [PATCH 4/9] 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 4744e89fd3..0c0cd4c035 100644 --- a/lnwire/dyn_propose.go +++ b/lnwire/dyn_propose.go @@ -307,3 +307,87 @@ func (dp *DynPropose) Decode(r io.Reader, _ uint32) error { func (dp *DynPropose) MsgType() MessageType { return MsgDynPropose } + +// 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 4fd8524cf0e8e77eb5b7a72feb68db94783757fc Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Mon, 7 Oct 2024 15:37:30 +0200 Subject: [PATCH 5/9] lnwire: remove kickoff feerate from propose/commit --- lnwire/dyn_commit.go | 21 +-------------------- lnwire/dyn_propose.go | 38 +------------------------------------- lnwire/lnwire_test.go | 14 -------------- 3 files changed, 2 insertions(+), 71 deletions(-) diff --git a/lnwire/dyn_commit.go b/lnwire/dyn_commit.go index 5684473b3c..9af3a37db4 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" - "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 0c0cd4c035..25c1bceb92 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" - "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. @@ -160,14 +150,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...) @@ -240,15 +222,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) @@ -287,11 +264,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 @@ -368,14 +340,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/lnwire_test.go b/lnwire/lnwire_test.go index 4eff6c47bd..85ecd2d8df 100644 --- a/lnwire/lnwire_test.go +++ b/lnwire/lnwire_test.go @@ -23,7 +23,6 @@ import ( "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" "github.com/lightningnetwork/lnd/fn" - "github.com/lightningnetwork/lnd/lnwallet/chainfee" "github.com/lightningnetwork/lnd/tlv" "github.com/lightningnetwork/lnd/tor" "github.com/stretchr/testify/assert" @@ -862,11 +861,6 @@ func TestLightningWireProtocol(t *testing.T) { dp.ChannelType = fn.Some(v) } - if rand.Uint32()%2 == 0 { - v := chainfee.SatPerKWeight(rand.Uint32()) - dp.KickoffFeerate = fn.Some(v) - } - v[0] = reflect.ValueOf(dp) }, MsgDynReject: func(v []reflect.Value, r *rand.Rand) { @@ -906,9 +900,6 @@ func TestLightningWireProtocol(t *testing.T) { features.Set(FeatureBit(DPChannelType)) } - if rand.Uint32()%2 == 0 { - features.Set(FeatureBit(DPKickoffFeerate)) - } dr.UpdateRejections = *features v[0] = reflect.ValueOf(dr) @@ -967,11 +958,6 @@ func TestLightningWireProtocol(t *testing.T) { dc.ChannelType = fn.Some(v) } - if rand.Uint32()%2 == 0 { - v := chainfee.SatPerKWeight(rand.Uint32()) - dc.KickoffFeerate = fn.Some(v) - } - v[0] = reflect.ValueOf(dc) }, MsgKickoffSig: func(v []reflect.Value, r *rand.Rand) { From 17c94349e41540358c91e733ab9c827638b09991 Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Tue, 15 Oct 2024 19:55:11 -0600 Subject: [PATCH 6/9] lnwire: remove FundingKey from DynPropose and DynCommit --- lnwire/dyn_commit.go | 20 +------------------- lnwire/dyn_propose.go | 36 +----------------------------------- lnwire/lnwire_test.go | 14 -------------- 3 files changed, 2 insertions(+), 68 deletions(-) diff --git a/lnwire/dyn_commit.go b/lnwire/dyn_commit.go index 9af3a37db4..fbe3aa70e5 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" "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 25c1bceb92..f0fd6ab680 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" "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] @@ -133,14 +124,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( @@ -211,11 +194,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, @@ -224,8 +202,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) @@ -258,9 +235,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) } @@ -323,14 +297,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/lnwire_test.go b/lnwire/lnwire_test.go index 85ecd2d8df..36e03b2e76 100644 --- a/lnwire/lnwire_test.go +++ b/lnwire/lnwire_test.go @@ -851,11 +851,6 @@ func TestLightningWireProtocol(t *testing.T) { dp.MaxAcceptedHTLCs = fn.Some(v) } - if rand.Uint32()%2 == 0 { - v, _ := btcec.NewPrivateKey() - dp.FundingKey = fn.Some(*v.PubKey()) - } - if rand.Uint32()%2 == 0 { v := ChannelType(*NewRawFeatureVector()) dp.ChannelType = fn.Some(v) @@ -892,10 +887,6 @@ func TestLightningWireProtocol(t *testing.T) { features.Set(FeatureBit(DPMaxAcceptedHtlcs)) } - if rand.Uint32()%2 == 0 { - features.Set(FeatureBit(DPFundingPubkey)) - } - if rand.Uint32()%2 == 0 { features.Set(FeatureBit(DPChannelType)) } @@ -948,11 +939,6 @@ func TestLightningWireProtocol(t *testing.T) { dc.MaxAcceptedHTLCs = fn.Some(v) } - if rand.Uint32()%2 == 0 { - v, _ := btcec.NewPrivateKey() - dc.FundingKey = fn.Some(*v.PubKey()) - } - if rand.Uint32()%2 == 0 { v := ChannelType(*NewRawFeatureVector()) dc.ChannelType = fn.Some(v) From ecdcf6506192f3918ce17aad479c4fd0ceae3483 Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Tue, 15 Oct 2024 20:34:17 -0600 Subject: [PATCH 7/9] lnwire: add HtlcMinimum to DynPropose and DynCommit --- lnwire/dyn_commit.go | 19 ++++++++++++++++++- lnwire/dyn_propose.go | 35 ++++++++++++++++++++++++++++++++++- lnwire/lnwire_test.go | 4 ++++ 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/lnwire/dyn_commit.go b/lnwire/dyn_commit.go index fbe3aa70e5..8ba08507dd 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 f0fd6ab680..a2d59a07dd 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] @@ -102,6 +110,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( @@ -181,6 +197,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, @@ -202,7 +223,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) @@ -226,6 +248,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)) } @@ -275,6 +300,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( diff --git a/lnwire/lnwire_test.go b/lnwire/lnwire_test.go index 36e03b2e76..f69051ad22 100644 --- a/lnwire/lnwire_test.go +++ b/lnwire/lnwire_test.go @@ -873,6 +873,10 @@ func TestLightningWireProtocol(t *testing.T) { ) } + if rand.Uint32()%2 == 0 { + features.Set(FeatureBit(DPHtlcMinimumMsat)) + } + if rand.Uint32()%2 == 0 { features.Set( FeatureBit(DPChannelReserveSatoshis), From b3ed9a64c66d4ff7cbf36c0677c901711d52a2b8 Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Tue, 15 Oct 2024 20:36:05 -0600 Subject: [PATCH 8/9] 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 a2d59a07dd..bd8372e207 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 5352fed695d47d21a1061f3d880a0e18422fd97f Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Wed, 16 Oct 2024 18:21:00 -0600 Subject: [PATCH 9/9] lnwire: convert DynPropose and DynCommit to use typed tlv records --- lnwire/dyn_commit.go | 176 ++++++---------------- lnwire/dyn_propose.go | 331 +++++++++++++----------------------------- lnwire/lnwire_test.go | 85 +++++++---- 3 files changed, 197 insertions(+), 395 deletions(-) diff --git a/lnwire/dyn_commit.go b/lnwire/dyn_commit.go index 8ba08507dd..73b992f617 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" "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 bd8372e207..a38df36cae 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" "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 @@ -93,76 +62,14 @@ var _ Message = (*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 } @@ -187,81 +94,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 chanTypeScratch ChannelType - chanType := tlv.MakeDynamicRecord( - DPChannelType, &chanTypeScratch, chanTypeScratch.featureBitLen, - channelTypeEncoder, channelTypeDecoder, + 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, ) - - // 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 { @@ -283,74 +161,67 @@ func (dp *DynPropose) MsgType() MessageType { // 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) + producers := dynProposeRecords(dp) - tlvStream, err := tlv.NewStream(tlvRecords...) + var extra ExtraOpaqueData + err := extra.PackRecords(producers...) if err != nil { return nil, err } - var outBuf bytes.Buffer - err = tlvStream.Encode(&outBuf) - if err != nil { - return nil, err - } + 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 outBuf.Bytes(), nil + return recordProducers } diff --git a/lnwire/lnwire_test.go b/lnwire/lnwire_test.go index f69051ad22..156c057638 100644 --- a/lnwire/lnwire_test.go +++ b/lnwire/lnwire_test.go @@ -827,72 +827,89 @@ func TestLightningWireProtocol(t *testing.T) { rand.Read(dp.ChanID[:]) if rand.Uint32()%2 == 0 { - v := btcutil.Amount(rand.Uint32()) - dp.DustLimit = fn.Some(v) + rec := dp.DustLimit.Zero() + rec.Val = btcutil.Amount(rand.Uint32()) + dp.DustLimit = tlv.SomeRecordT(rec) } if rand.Uint32()%2 == 0 { - v := MilliSatoshi(rand.Uint32()) - dp.MaxValueInFlight = fn.Some(v) + rec := dp.MaxValueInFlight.Zero() + rec.Val = MilliSatoshi(rand.Uint32()) + dp.MaxValueInFlight = tlv.SomeRecordT(rec) } if rand.Uint32()%2 == 0 { - v := btcutil.Amount(rand.Uint32()) - dp.ChannelReserve = fn.Some(v) + rec := dp.ChannelReserve.Zero() + rec.Val = btcutil.Amount(rand.Uint32()) + dp.ChannelReserve = tlv.SomeRecordT(rec) } if rand.Uint32()%2 == 0 { - v := uint16(rand.Uint32()) - dp.CsvDelay = fn.Some(v) + rec := dp.CsvDelay.Zero() + rec.Val = uint16(rand.Uint32()) + dp.CsvDelay = tlv.SomeRecordT(rec) } if rand.Uint32()%2 == 0 { - v := uint16(rand.Uint32()) - dp.MaxAcceptedHTLCs = fn.Some(v) + rec := dp.MaxAcceptedHTLCs.Zero() + rec.Val = uint16(rand.Uint32()) + dp.MaxAcceptedHTLCs = tlv.SomeRecordT(rec) } if rand.Uint32()%2 == 0 { - v := ChannelType(*NewRawFeatureVector()) - dp.ChannelType = fn.Some(v) + rec := dp.ChannelType.Zero() + rec.Val = ChannelType(*NewRawFeatureVector()) + dp.ChannelType = tlv.SomeRecordT(rec) } v[0] = reflect.ValueOf(dp) }, MsgDynReject: func(v []reflect.Value, r *rand.Rand) { + var dp DynPropose var dr DynReject rand.Read(dr.ChanID[:]) features := NewRawFeatureVector() if rand.Uint32()%2 == 0 { - features.Set(FeatureBit(DPDustLimitSatoshis)) + features.Set(FeatureBit(dp.DustLimit.TlvType())) } if rand.Uint32()%2 == 0 { features.Set( - FeatureBit(DPMaxHtlcValueInFlightMsat), + FeatureBit( + dp.MaxValueInFlight.TlvType(), + ), ) } if rand.Uint32()%2 == 0 { - features.Set(FeatureBit(DPHtlcMinimumMsat)) + features.Set( + FeatureBit(dp.HtlcMinimum.TlvType()), + ) } if rand.Uint32()%2 == 0 { features.Set( - FeatureBit(DPChannelReserveSatoshis), + FeatureBit(dp.ChannelReserve.TlvType()), ) } if rand.Uint32()%2 == 0 { - features.Set(FeatureBit(DPToSelfDelay)) + features.Set(FeatureBit(dp.CsvDelay.TlvType())) } if rand.Uint32()%2 == 0 { - features.Set(FeatureBit(DPMaxAcceptedHtlcs)) + features.Set( + FeatureBit( + dp.MaxAcceptedHTLCs.TlvType(), + ), + ) } if rand.Uint32()%2 == 0 { - features.Set(FeatureBit(DPChannelType)) + features.Set( + FeatureBit(dp.ChannelType.TlvType()), + ) } dr.UpdateRejections = *features @@ -919,33 +936,39 @@ func TestLightningWireProtocol(t *testing.T) { rand.Read(dc.Sig.bytes[:]) if rand.Uint32()%2 == 0 { - v := btcutil.Amount(rand.Uint32()) - dc.DustLimit = fn.Some(v) + rec := dc.DustLimit.Zero() + rec.Val = btcutil.Amount(rand.Uint32()) + dc.DustLimit = tlv.SomeRecordT(rec) } if rand.Uint32()%2 == 0 { - v := MilliSatoshi(rand.Uint32()) - dc.MaxValueInFlight = fn.Some(v) + rec := dc.MaxValueInFlight.Zero() + rec.Val = MilliSatoshi(rand.Uint32()) + dc.MaxValueInFlight = tlv.SomeRecordT(rec) } if rand.Uint32()%2 == 0 { - v := btcutil.Amount(rand.Uint32()) - dc.ChannelReserve = fn.Some(v) + rec := dc.ChannelReserve.Zero() + rec.Val = btcutil.Amount(rand.Uint32()) + dc.ChannelReserve = tlv.SomeRecordT(rec) } if rand.Uint32()%2 == 0 { - v := uint16(rand.Uint32()) - dc.CsvDelay = fn.Some(v) + rec := dc.CsvDelay.Zero() + rec.Val = uint16(rand.Uint32()) + dc.CsvDelay = tlv.SomeRecordT(rec) } if rand.Uint32()%2 == 0 { - v := uint16(rand.Uint32()) - dc.MaxAcceptedHTLCs = fn.Some(v) + rec := dc.MaxAcceptedHTLCs.Zero() + rec.Val = uint16(rand.Uint32()) + dc.MaxAcceptedHTLCs = tlv.SomeRecordT(rec) } if rand.Uint32()%2 == 0 { - v := ChannelType(*NewRawFeatureVector()) - dc.ChannelType = fn.Some(v) + rec := dc.ChannelType.Zero() + rec.Val = ChannelType(*NewRawFeatureVector()) + dc.ChannelType = tlv.SomeRecordT(rec) } v[0] = reflect.ValueOf(dc)