From f3943fb530a7edb5cb9aa57d24b0ee5508b92c2d Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Fri, 13 Sep 2024 16:27:59 -0700 Subject: [PATCH 01/15] 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 b0cc1198e94..4744e89fd39 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 02/15] 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 24f23a228dd..b3c37da75ab 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 03/15] 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 00000000000..5684473b3cf --- /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 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/lnwire_test.go b/lnwire/lnwire_test.go index 6b9630f58ad..4eff6c47bdb 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 68b09692e55..34effc85155 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 04/15] 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 4744e89fd39..0c0cd4c0351 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 05/15] 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 5684473b3cf..9af3a37db4f 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 0c0cd4c0351..25c1bceb92e 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 4eff6c47bdb..85ecd2d8df4 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 06/15] 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 9af3a37db4f..fbe3aa70e59 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 25c1bceb92e..f0fd6ab6808 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 85ecd2d8df4..36e03b2e769 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 07/15] 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 fbe3aa70e59..8ba08507dde 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 f0fd6ab6808..a2d59a07ddd 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 36e03b2e769..f69051ad228 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 08/15] 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 a2d59a07ddd..bd8372e2079 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 09/15] 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 8ba08507dde..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" "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 bd8372e2079..a38df36caef 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 f69051ad228..156c0576381 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) From c21b92bc4b2fe4037b134ce6181eab0d06e902f7 Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Mon, 19 Aug 2024 15:07:52 -0600 Subject: [PATCH 10/15] multi: pack LocalChanCfg/RemoteChanCfg into Dual --- chanbackup/single.go | 4 +- chanbackup/single_test.go | 7 +- channeldb/channel.go | 19 +-- channeldb/channel_test.go | 8 +- channeldb/db.go | 2 +- channeldb/db_test.go | 20 ++- chanrestore.go | 7 +- contractcourt/breach_arbitrator_test.go | 17 ++- contractcourt/chain_watcher.go | 23 +-- contractcourt/chain_watcher_test.go | 3 +- contractcourt/commit_sweep_resolver.go | 2 +- funding/manager.go | 29 ++-- htlcswitch/link.go | 4 +- htlcswitch/test_utils.go | 12 +- lnwallet/aux_leaf_store.go | 4 +- lnwallet/channel.go | 185 +++++++++++++----------- lnwallet/channel_test.go | 137 +++++++++--------- lnwallet/commitment.go | 22 +-- lnwallet/test_utils.go | 12 +- lnwallet/transactions_test.go | 12 +- lnwallet/wallet.go | 14 +- peer/test_utils.go | 12 +- routing/localchans/manager.go | 8 +- routing/localchans/manager_test.go | 54 ++++--- rpcserver.go | 24 +-- 25 files changed, 354 insertions(+), 287 deletions(-) diff --git a/chanbackup/single.go b/chanbackup/single.go index b741320b078..88f9ded27b6 100644 --- a/chanbackup/single.go +++ b/chanbackup/single.go @@ -296,8 +296,8 @@ func NewSingle(channel *channeldb.OpenChannel, RemoteNodePub: channel.IdentityPub, Addresses: nodeAddrs, Capacity: channel.Capacity, - LocalChanCfg: channel.LocalChanCfg, - RemoteChanCfg: channel.RemoteChanCfg, + LocalChanCfg: channel.ChanCfgs.Local, + RemoteChanCfg: channel.ChanCfgs.Remote, ShaChainRootDesc: shaChainRootDesc, } diff --git a/chanbackup/single_test.go b/chanbackup/single_test.go index d2212bd859c..dd5bd1a816a 100644 --- a/chanbackup/single_test.go +++ b/chanbackup/single_test.go @@ -16,6 +16,7 @@ import ( "github.com/lightningnetwork/lnd/fn" "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/lnencrypt" + "github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/shachain" "github.com/stretchr/testify/require" @@ -241,11 +242,13 @@ func genRandomOpenChannelShell() (*channeldb.OpenChannel, error) { ), ThawHeight: rand.Uint32(), IdentityPub: pub, - LocalChanCfg: localCfg, - RemoteChanCfg: remoteCfg, LocalCommitment: localCommit, RevocationProducer: shaChainProducer, TapscriptRoot: tapscriptRootOption, + ChanCfgs: lntypes.Dual[channeldb.ChannelConfig]{ + Local: localCfg, + Remote: remoteCfg, + }, }, nil } diff --git a/channeldb/channel.go b/channeldb/channel.go index c21716a4560..5a59be91562 100644 --- a/channeldb/channel.go +++ b/channeldb/channel.go @@ -938,11 +938,8 @@ type OpenChannel struct { // opening. InitialRemoteBalance lnwire.MilliSatoshi - // LocalChanCfg is the channel configuration for the local node. - LocalChanCfg ChannelConfig - - // RemoteChanCfg is the channel configuration for the remote node. - RemoteChanCfg ChannelConfig + // ChanCfgs is the channel configuration for the local and remote nodes. + ChanCfgs lntypes.Dual[ChannelConfig] // LocalCommitment is the current local commitment state for the local // party. This is stored distinct from the state of the remote party @@ -1823,7 +1820,7 @@ func (c *OpenChannel) ChanSyncMsg() (*lnwire.ChannelReestablish, error) { } nextNonce, err := NewMusigVerificationNonce( - c.LocalChanCfg.MultiSigKey.PubKey, + c.ChanCfgs.Local.MultiSigKey.PubKey, nextLocalCommitHeight, taprootRevProducer, ) if err != nil { @@ -4112,7 +4109,7 @@ func putChannelCloseSummary(tx kvdb.RwTx, chanID []byte, summary.RemoteCurrentRevocation = lastChanState.RemoteCurrentRevocation summary.RemoteNextRevocation = lastChanState.RemoteNextRevocation - summary.LocalChanConfig = lastChanState.LocalChanCfg + summary.LocalChanConfig = lastChanState.ChanCfgs.Local var b bytes.Buffer if err := serializeChannelCloseSummary(&b, summary); err != nil { @@ -4302,10 +4299,10 @@ func putChanInfo(chanBucket kvdb.RwBucket, channel *OpenChannel) error { } } - if err := writeChanConfig(&w, &channel.LocalChanCfg); err != nil { + if err := writeChanConfig(&w, &channel.ChanCfgs.Local); err != nil { return err } - if err := writeChanConfig(&w, &channel.RemoteChanCfg); err != nil { + if err := writeChanConfig(&w, &channel.ChanCfgs.Remote); err != nil { return err } @@ -4484,10 +4481,10 @@ func fetchChanInfo(chanBucket kvdb.RBucket, channel *OpenChannel) error { } } - if err := readChanConfig(r, &channel.LocalChanCfg); err != nil { + if err := readChanConfig(r, &channel.ChanCfgs.Local); err != nil { return err } - if err := readChanConfig(r, &channel.RemoteChanCfg); err != nil { + if err := readChanConfig(r, &channel.ChanCfgs.Remote); err != nil { return err } diff --git a/channeldb/channel_test.go b/channeldb/channel_test.go index e92692201d8..91ad13e97ec 100644 --- a/channeldb/channel_test.go +++ b/channeldb/channel_test.go @@ -339,8 +339,10 @@ func createTestChannelState(t *testing.T, cdb *ChannelStateDB) *OpenChannel { IsPending: true, IdentityPub: pubKey, Capacity: btcutil.Amount(10000), - LocalChanCfg: localCfg, - RemoteChanCfg: remoteCfg, + ChanCfgs: lntypes.Dual[ChannelConfig]{ + Local: localCfg, + Remote: remoteCfg, + }, TotalMSatSent: 8, TotalMSatReceived: 2, LocalCommitment: ChannelCommitment{ @@ -1025,7 +1027,7 @@ func TestFetchClosedChannels(t *testing.T) { TimeLockedBalance: state.RemoteCommitment.LocalBalance.ToSatoshis() + 10000, CloseType: RemoteForceClose, IsPending: true, - LocalChanConfig: state.LocalChanCfg, + LocalChanConfig: state.ChanCfgs.Local, } if err := state.CloseChannel(summary); err != nil { t.Fatalf("unable to close channel: %v", err) diff --git a/channeldb/db.go b/channeldb/db.go index 92e0498eceb..715eb38510f 100644 --- a/channeldb/db.go +++ b/channeldb/db.go @@ -1430,7 +1430,7 @@ func (c *ChannelStateDB) AbandonChannel(chanPoint *wire.OutPoint, ShortChanID: dbChan.ShortChanID(), RemoteCurrentRevocation: dbChan.RemoteCurrentRevocation, RemoteNextRevocation: dbChan.RemoteNextRevocation, - LocalChanConfig: dbChan.LocalChanCfg, + LocalChanConfig: dbChan.ChanCfgs.Local, } // Finally, we'll close the channel in the DB, and return back to the diff --git a/channeldb/db_test.go b/channeldb/db_test.go index d8113db8306..8dda4927588 100644 --- a/channeldb/db_test.go +++ b/channeldb/db_test.go @@ -296,6 +296,16 @@ func genRandomChannelShell() (*ChannelShell, error) { CsvDelay: uint16(rand.Int63()), } + localChanCfg := ChannelConfig{ + CommitmentParams: commitParams, + PaymentBasePoint: keychain.KeyDescriptor{ + KeyLocator: keychain.KeyLocator{ + Family: keychain.KeyFamily(rand.Int63()), + Index: uint32(rand.Int63()), + }, + }, + } + return &ChannelShell{ NodeAddrs: []net.Addr{&net.TCPAddr{ IP: net.ParseIP("127.0.0.1"), @@ -309,14 +319,8 @@ func genRandomChannelShell() (*ChannelShell, error) { uint64(rand.Int63()), ), IdentityPub: pub, - LocalChanCfg: ChannelConfig{ - CommitmentParams: commitParams, - PaymentBasePoint: keychain.KeyDescriptor{ - KeyLocator: keychain.KeyLocator{ - Family: keychain.KeyFamily(rand.Int63()), - Index: uint32(rand.Int63()), - }, - }, + ChanCfgs: lntypes.Dual[ChannelConfig]{ + Local: localChanCfg, }, RemoteCurrentRevocation: pub, IsPending: false, diff --git a/chanrestore.go b/chanrestore.go index 5b221c105a5..1fe80119954 100644 --- a/chanrestore.go +++ b/chanrestore.go @@ -12,6 +12,7 @@ import ( "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/contractcourt" "github.com/lightningnetwork/lnd/keychain" + "github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/shachain" ) @@ -187,12 +188,14 @@ func (c *chanDBRestorer) openChannelShell(backup chanbackup.Single) ( ShortChannelID: backup.ShortChannelID, IdentityPub: backup.RemoteNodePub, IsPending: false, - LocalChanCfg: backup.LocalChanCfg, - RemoteChanCfg: backup.RemoteChanCfg, RemoteCurrentRevocation: backup.RemoteNodePub, RevocationStore: shachain.NewRevocationStore(), RevocationProducer: shaChainProducer, ThawHeight: backup.LeaseExpiry, + ChanCfgs: lntypes.Dual[channeldb.ChannelConfig]{ + Local: backup.LocalChanCfg, + Remote: backup.RemoteChanCfg, + }, }, } diff --git a/contractcourt/breach_arbitrator_test.go b/contractcourt/breach_arbitrator_test.go index bd4ad856831..faf36f5e6f9 100644 --- a/contractcourt/breach_arbitrator_test.go +++ b/contractcourt/breach_arbitrator_test.go @@ -28,6 +28,7 @@ import ( "github.com/lightningnetwork/lnd/lntest/channels" "github.com/lightningnetwork/lnd/lntest/mock" "github.com/lightningnetwork/lnd/lntest/wait" + "github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet/chainfee" "github.com/lightningnetwork/lnd/lnwire" @@ -1636,7 +1637,7 @@ func testBreachSpends(t *testing.T, test breachTest) { ShortChanID: state.ShortChanID(), RemoteCurrentRevocation: state.RemoteCurrentRevocation, RemoteNextRevocation: state.RemoteNextRevocation, - LocalChanConfig: state.LocalChanCfg, + LocalChanConfig: state.ChanCfgs.Local, }) require.NoError(t, err, "unable to close channel") @@ -1850,7 +1851,7 @@ func TestBreachDelayedJusticeConfirmation(t *testing.T) { ShortChanID: state.ShortChanID(), RemoteCurrentRevocation: state.RemoteCurrentRevocation, RemoteNextRevocation: state.RemoteNextRevocation, - LocalChanConfig: state.LocalChanCfg, + LocalChanConfig: state.ChanCfgs.Local, }) require.NoError(t, err, "unable to close channel") @@ -2333,8 +2334,10 @@ func createInitChannels(t *testing.T) ( ) aliceChannelState := &channeldb.OpenChannel{ - LocalChanCfg: aliceCfg, - RemoteChanCfg: bobCfg, + ChanCfgs: lntypes.Dual[channeldb.ChannelConfig]{ + Local: aliceCfg, + Remote: bobCfg, + }, IdentityPub: aliceKeyPub, FundingOutpoint: *prevOut, ShortChannelID: shortChanID, @@ -2351,8 +2354,10 @@ func createInitChannels(t *testing.T) ( FundingTxn: channels.TestFundingTx, } bobChannelState := &channeldb.OpenChannel{ - LocalChanCfg: bobCfg, - RemoteChanCfg: aliceCfg, + ChanCfgs: lntypes.Dual[channeldb.ChannelConfig]{ + Local: bobCfg, + Remote: aliceCfg, + }, IdentityPub: bobKeyPub, FundingOutpoint: *prevOut, ShortChannelID: shortChanID, diff --git a/contractcourt/chain_watcher.go b/contractcourt/chain_watcher.go index 808f41f2eee..1997496808b 100644 --- a/contractcourt/chain_watcher.go +++ b/contractcourt/chain_watcher.go @@ -250,13 +250,13 @@ func newChainWatcher(cfg chainWatcherConfig) (*chainWatcher, error) { chanState := cfg.chanState if chanState.IsInitiator { stateHint = lnwallet.DeriveStateHintObfuscator( - chanState.LocalChanCfg.PaymentBasePoint.PubKey, - chanState.RemoteChanCfg.PaymentBasePoint.PubKey, + chanState.ChanCfgs.Local.PaymentBasePoint.PubKey, + chanState.ChanCfgs.Remote.PaymentBasePoint.PubKey, ) } else { stateHint = lnwallet.DeriveStateHintObfuscator( - chanState.RemoteChanCfg.PaymentBasePoint.PubKey, - chanState.LocalChanCfg.PaymentBasePoint.PubKey, + chanState.ChanCfgs.Remote.PaymentBasePoint.PubKey, + chanState.ChanCfgs.Local.PaymentBasePoint.PubKey, ) } @@ -306,8 +306,8 @@ func (c *chainWatcher) Start() error { } } - localKey := chanState.LocalChanCfg.MultiSigKey.PubKey - remoteKey := chanState.RemoteChanCfg.MultiSigKey.PubKey + localKey := chanState.ChanCfgs.Local.MultiSigKey.PubKey + remoteKey := chanState.ChanCfgs.Remote.MultiSigKey.PubKey var ( err error @@ -426,7 +426,8 @@ func (c *chainWatcher) handleUnknownLocalState( // revoke our own commitment. commitKeyRing := lnwallet.DeriveCommitmentKeys( commitPoint, lntypes.Local, c.cfg.chanState.ChanType, - &c.cfg.chanState.LocalChanCfg, &c.cfg.chanState.RemoteChanCfg, + &c.cfg.chanState.ChanCfgs.Local, + &c.cfg.chanState.ChanCfgs.Remote, ) auxResult, err := fn.MapOptionZ( @@ -476,7 +477,7 @@ func (c *chainWatcher) handleUnknownLocalState( localScript, err := lnwallet.CommitScriptToSelf( c.cfg.chanState.ChanType, c.cfg.chanState.IsInitiator, commitKeyRing.ToLocalKey, commitKeyRing.RevocationKey, - uint32(c.cfg.chanState.LocalChanCfg.CsvDelay), leaseExpiry, + uint32(c.cfg.chanState.ChanCfgs.Local.CsvDelay), leaseExpiry, localAuxLeaf, ) if err != nil { @@ -1107,7 +1108,7 @@ func (c *chainWatcher) dispatchCooperativeClose(commitSpend *chainntnfs.SpendDet IsPending: true, RemoteCurrentRevocation: c.cfg.chanState.RemoteCurrentRevocation, RemoteNextRevocation: c.cfg.chanState.RemoteNextRevocation, - LocalChanConfig: c.cfg.chanState.LocalChanCfg, + LocalChanConfig: c.cfg.chanState.ChanCfgs.Local, } // Attempt to add a channel sync message to the close summary. @@ -1172,7 +1173,7 @@ func (c *chainWatcher) dispatchLocalForceClose( CloseHeight: uint32(commitSpend.SpendingHeight), RemoteCurrentRevocation: c.cfg.chanState.RemoteCurrentRevocation, RemoteNextRevocation: c.cfg.chanState.RemoteNextRevocation, - LocalChanConfig: c.cfg.chanState.LocalChanCfg, + LocalChanConfig: c.cfg.chanState.ChanCfgs.Local, } resolutions, err := forceClose.ContractResolutions.UnwrapOrErr( @@ -1326,7 +1327,7 @@ func (c *chainWatcher) dispatchContractBreach(spendEvent *chainntnfs.SpendDetail ShortChanID: c.cfg.chanState.ShortChanID(), RemoteCurrentRevocation: c.cfg.chanState.RemoteCurrentRevocation, RemoteNextRevocation: c.cfg.chanState.RemoteNextRevocation, - LocalChanConfig: c.cfg.chanState.LocalChanCfg, + LocalChanConfig: c.cfg.chanState.ChanCfgs.Local, } // Attempt to add a channel sync message to the close summary. diff --git a/contractcourt/chain_watcher_test.go b/contractcourt/chain_watcher_test.go index baea8d8738c..947f17cb0b6 100644 --- a/contractcourt/chain_watcher_test.go +++ b/contractcourt/chain_watcher_test.go @@ -347,7 +347,8 @@ func TestChainWatcherDataLossProtect(t *testing.T) { // key for this output. sweepTweak := input.SingleTweakBytes( dlpPoint, - aliceChannel.State().LocalChanCfg.PaymentBasePoint.PubKey, + //nolint:lll + aliceChannel.State().ChanCfgs.Local.PaymentBasePoint.PubKey, ) commitResolution := uniClose.CommitResolution resolutionTweak := commitResolution.SelfOutputSignDesc.SingleTweak diff --git a/contractcourt/commit_sweep_resolver.go b/contractcourt/commit_sweep_resolver.go index 4b47a342948..3526ae5574b 100644 --- a/contractcourt/commit_sweep_resolver.go +++ b/contractcourt/commit_sweep_resolver.go @@ -471,7 +471,7 @@ func (c *commitSweepResolver) SupplementState(state *channeldb.OpenChannel) { if state.ChanType.HasLeaseExpiration() { c.leaseExpiry = state.ThawHeight } - c.localChanCfg = state.LocalChanCfg + c.localChanCfg = state.ChanCfgs.Local c.channelInitiator = state.IsInitiator c.chanType = state.ChanType } diff --git a/funding/manager.go b/funding/manager.go index 1fa90c6932b..aa52f51e8dd 100644 --- a/funding/manager.go +++ b/funding/manager.go @@ -2552,7 +2552,7 @@ func (f *Manager) fundeeProcessFundingCreated(peer lnpeer.Peer, SettledBalance: localBalance, RemoteCurrentRevocation: completeChan.RemoteCurrentRevocation, RemoteNextRevocation: completeChan.RemoteNextRevocation, - LocalChanConfig: completeChan.LocalChanCfg, + LocalChanConfig: completeChan.ChanCfgs.Local, } // Close the channel with us as the initiator because we are @@ -2917,7 +2917,7 @@ func (f *Manager) fundingTimeout(c *channeldb.OpenChannel, CloseType: channeldb.FundingCanceled, RemoteCurrentRevocation: c.RemoteCurrentRevocation, RemoteNextRevocation: c.RemoteNextRevocation, - LocalChanConfig: c.LocalChanCfg, + LocalChanConfig: c.ChanCfgs.Local, } // Close the channel with us as the initiator because we are timing the @@ -3017,8 +3017,8 @@ func (f *Manager) waitForFundingWithTimeout( // makeFundingScript re-creates the funding script for the funding transaction // of the target channel. func makeFundingScript(channel *channeldb.OpenChannel) ([]byte, error) { - localKey := channel.LocalChanCfg.MultiSigKey.PubKey - remoteKey := channel.RemoteChanCfg.MultiSigKey.PubKey + localKey := channel.ChanCfgs.Local.MultiSigKey.PubKey + remoteKey := channel.ChanCfgs.Remote.MultiSigKey.PubKey if channel.ChanType.IsTaproot() { pkScript, _, err := input.GenTaprootFundingScript( @@ -3510,7 +3510,7 @@ func (f *Manager) extractAnnounceParams(c *channeldb.OpenChannel) ( // we'll use this value within our ChannelUpdate. This constraint is // originally set by the remote node, as it will be the one that will // need to determine the smallest HTLC it deems economically relevant. - fwdMinHTLC := c.LocalChanCfg.MinHTLC + fwdMinHTLC := c.ChanCfgs.Local.MinHTLC // We don't necessarily want to go as low as the remote party allows. // Check it against our default forwarding policy. @@ -3521,7 +3521,7 @@ func (f *Manager) extractAnnounceParams(c *channeldb.OpenChannel) ( // We'll obtain the max HTLC value we can forward in our direction, as // we'll use this value within our ChannelUpdate. This value must be <= // channel capacity and <= the maximum in-flight msats set by the peer. - fwdMaxHTLC := c.LocalChanCfg.MaxPendingAmount + fwdMaxHTLC := c.ChanCfgs.Local.MaxPendingAmount capacityMSat := lnwire.NewMSatFromSatoshis(c.Capacity) if fwdMaxHTLC > capacityMSat { fwdMaxHTLC = capacityMSat @@ -3549,8 +3549,8 @@ func (f *Manager) addToGraph(completeChan *channeldb.OpenChannel, ann, err := f.newChanAnnouncement( f.cfg.IDKey, completeChan.IdentityPub, - &completeChan.LocalChanCfg.MultiSigKey, - completeChan.RemoteChanCfg.MultiSigKey.PubKey, *shortChanID, + &completeChan.ChanCfgs.Local.MultiSigKey, + completeChan.ChanCfgs.Remote.MultiSigKey.PubKey, *shortChanID, chanID, fwdMinHTLC, fwdMaxHTLC, ourPolicy, completeChan.ChanType, ) @@ -3743,8 +3743,8 @@ func (f *Manager) annAfterSixConfs(completeChan *channeldb.OpenChannel, // public and usable for other nodes for routing. err = f.announceChannel( f.cfg.IDKey, completeChan.IdentityPub, - &completeChan.LocalChanCfg.MultiSigKey, - completeChan.RemoteChanCfg.MultiSigKey.PubKey, + &completeChan.ChanCfgs.Local.MultiSigKey, + completeChan.ChanCfgs.Remote.MultiSigKey.PubKey, *shortChanID, chanID, completeChan.ChanType, ) if err != nil { @@ -3864,7 +3864,7 @@ func genFirstStateMusigNonce(channel *channeldb.OpenChannel, // We use the _next_ commitment height here as we need to generate the // nonce for the next state the remote party will sign for us. verNonce, err := channeldb.NewMusigVerificationNonce( - channel.LocalChanCfg.MultiSigKey.PubKey, + channel.ChanCfgs.Local.MultiSigKey.PubKey, channel.LocalCommitment.CommitHeight+1, musig2ShaChain, ) @@ -4257,7 +4257,7 @@ func (f *Manager) ensureInitialForwardingPolicy(chanID lnwire.ChannelID, "falling back to default values: %v", err) forwardingPolicy = f.defaultForwardingPolicy( - channel.LocalChanCfg.ChannelStateBounds, + channel.ChanCfgs.Local.ChannelStateBounds, ) needDBUpdate = true } @@ -4267,11 +4267,12 @@ func (f *Manager) ensureInitialForwardingPolicy(chanID lnwire.ChannelID, // still pending while updating to this version, we'll need to set the // values to the default values. if forwardingPolicy.MinHTLCOut == 0 { - forwardingPolicy.MinHTLCOut = channel.LocalChanCfg.MinHTLC + forwardingPolicy.MinHTLCOut = channel.ChanCfgs.Local.MinHTLC needDBUpdate = true } if forwardingPolicy.MaxHTLC == 0 { - forwardingPolicy.MaxHTLC = channel.LocalChanCfg.MaxPendingAmount + forwardingPolicy.MaxHTLC = + channel.ChanCfgs.Local.MaxPendingAmount needDBUpdate = true } diff --git a/htlcswitch/link.go b/htlcswitch/link.go index 57904600555..6a4a0306758 100644 --- a/htlcswitch/link.go +++ b/htlcswitch/link.go @@ -2946,8 +2946,8 @@ func (l *channelLink) getFeeRate() chainfee.SatPerKWeight { // // NOTE: Part of the dustHandler interface. func (l *channelLink) getDustClosure() dustClosure { - localDustLimit := l.channel.State().LocalChanCfg.DustLimit - remoteDustLimit := l.channel.State().RemoteChanCfg.DustLimit + localDustLimit := l.channel.State().ChanCfgs.Local.DustLimit + remoteDustLimit := l.channel.State().ChanCfgs.Remote.DustLimit chanType := l.channel.State().ChanType return dustHelper(chanType, localDustLimit, remoteDustLimit) diff --git a/htlcswitch/test_utils.go b/htlcswitch/test_utils.go index cdb4f1f4ea4..be8b935e93c 100644 --- a/htlcswitch/test_utils.go +++ b/htlcswitch/test_utils.go @@ -305,8 +305,10 @@ func createTestChannel(t *testing.T, alicePrivKey, bobPrivKey []byte, } aliceChannelState := &channeldb.OpenChannel{ - LocalChanCfg: aliceCfg, - RemoteChanCfg: bobCfg, + ChanCfgs: lntypes.Dual[channeldb.ChannelConfig]{ + Local: aliceCfg, + Remote: bobCfg, + }, IdentityPub: aliceKeyPub, FundingOutpoint: *prevOut, ChanType: channeldb.SingleFunderTweaklessBit, @@ -324,8 +326,10 @@ func createTestChannel(t *testing.T, alicePrivKey, bobPrivKey []byte, } bobChannelState := &channeldb.OpenChannel{ - LocalChanCfg: bobCfg, - RemoteChanCfg: aliceCfg, + ChanCfgs: lntypes.Dual[channeldb.ChannelConfig]{ + Local: bobCfg, + Remote: aliceCfg, + }, IdentityPub: bobKeyPub, FundingOutpoint: *prevOut, ChanType: channeldb.SingleFunderTweaklessBit, diff --git a/lnwallet/aux_leaf_store.go b/lnwallet/aux_leaf_store.go index c457a92509b..20fd311e3aa 100644 --- a/lnwallet/aux_leaf_store.go +++ b/lnwallet/aux_leaf_store.go @@ -112,8 +112,8 @@ func NewAuxChanState(chanState *channeldb.OpenChannel) AuxChanState { ShortChannelID: chanState.ShortChannelID, IsInitiator: chanState.IsInitiator, Capacity: chanState.Capacity, - LocalChanCfg: chanState.LocalChanCfg, - RemoteChanCfg: chanState.RemoteChanCfg, + LocalChanCfg: chanState.ChanCfgs.Local, + RemoteChanCfg: chanState.ChanCfgs.Remote, ThawHeight: chanState.ThawHeight, TapscriptRoot: chanState.TapscriptRoot, CustomBlob: chanState.CustomBlob, diff --git a/lnwallet/channel.go b/lnwallet/channel.go index fe4351c4764..bdc7c2afe2a 100644 --- a/lnwallet/channel.go +++ b/lnwallet/channel.go @@ -506,7 +506,7 @@ func (lc *LightningChannel) diskHtlcToPayDesc(feeRate chainfee.SatPerKWeight, // on-disk state snapshot. isDustLocal := HtlcIsDust( chanType, htlc.Incoming, lntypes.Local, feeRate, - htlc.Amt.ToSatoshis(), lc.channelState.LocalChanCfg.DustLimit, + htlc.Amt.ToSatoshis(), lc.channelState.ChanCfgs.Local.DustLimit, ) localCommitKeys := commitKeys.GetForParty(lntypes.Local) if !isDustLocal && localCommitKeys != nil { @@ -523,7 +523,8 @@ func (lc *LightningChannel) diskHtlcToPayDesc(feeRate chainfee.SatPerKWeight, } isDustRemote := HtlcIsDust( chanType, htlc.Incoming, lntypes.Remote, feeRate, - htlc.Amt.ToSatoshis(), lc.channelState.RemoteChanCfg.DustLimit, + htlc.Amt.ToSatoshis(), + lc.channelState.ChanCfgs.Remote.DustLimit, ) remoteCommitKeys := commitKeys.GetForParty(lntypes.Remote) if !isDustRemote && remoteCommitKeys != nil { @@ -646,16 +647,16 @@ func (lc *LightningChannel) diskCommitToMemCommit( commitKeys.SetForParty(lntypes.Local, DeriveCommitmentKeys( localCommitPoint, lntypes.Local, lc.channelState.ChanType, - &lc.channelState.LocalChanCfg, - &lc.channelState.RemoteChanCfg, + &lc.channelState.ChanCfgs.Local, + &lc.channelState.ChanCfgs.Remote, )) } if remoteCommitPoint != nil { commitKeys.SetForParty(lntypes.Remote, DeriveCommitmentKeys( remoteCommitPoint, lntypes.Remote, lc.channelState.ChanType, - &lc.channelState.LocalChanCfg, - &lc.channelState.RemoteChanCfg, + &lc.channelState.ChanCfgs.Local, + &lc.channelState.ChanCfgs.Remote, )) } @@ -708,9 +709,9 @@ func (lc *LightningChannel) diskCommitToMemCommit( customBlob: diskCommit.CustomBlob, } if whoseCommit.IsLocal() { - commit.dustLimit = lc.channelState.LocalChanCfg.DustLimit + commit.dustLimit = lc.channelState.ChanCfgs.Local.DustLimit } else { - commit.dustLimit = lc.channelState.RemoteChanCfg.DustLimit + commit.dustLimit = lc.channelState.ChanCfgs.Remote.DustLimit } return commit, nil @@ -1007,8 +1008,8 @@ func (lc *LightningChannel) createSignDesc() error { ) chanState := lc.channelState - localKey := chanState.LocalChanCfg.MultiSigKey.PubKey - remoteKey := chanState.RemoteChanCfg.MultiSigKey.PubKey + localKey := chanState.ChanCfgs.Local.MultiSigKey.PubKey + remoteKey := chanState.ChanCfgs.Remote.MultiSigKey.PubKey if chanState.ChanType.IsTaproot() { fundingPkScript, _, err = input.GenTaprootFundingScript( @@ -1038,7 +1039,7 @@ func (lc *LightningChannel) createSignDesc() error { Value: int64(lc.channelState.Capacity), } lc.signDesc = &input.SignDescriptor{ - KeyDesc: lc.channelState.LocalChanCfg.MultiSigKey, + KeyDesc: lc.channelState.ChanCfgs.Local.MultiSigKey, WitnessScript: multiSigScript, Output: &lc.fundingOutput, HashType: txscript.SigHashAll, @@ -1513,8 +1514,8 @@ func (lc *LightningChannel) restoreCommitState( pendingRemoteKeyChain = DeriveCommitmentKeys( pendingCommitPoint, lntypes.Remote, lc.channelState.ChanType, - &lc.channelState.LocalChanCfg, - &lc.channelState.RemoteChanCfg, + &lc.channelState.ChanCfgs.Local, + &lc.channelState.ChanCfgs.Remote, ) } @@ -1851,7 +1852,7 @@ func (lc *LightningChannel) restorePendingLocalUpdates( &logUpdate, lc.updateLogs.Remote, pendingHeight, chainfee.SatPerKWeight(pendingCommit.FeePerKw), pendingRemoteKeys, - lc.channelState.RemoteChanCfg.DustLimit, + lc.channelState.ChanCfgs.Remote.DustLimit, auxResult.AuxLeaves, ) if err != nil { @@ -2066,7 +2067,7 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64, // keys we'll need to reconstruct the commitment state, keyRing := DeriveCommitmentKeys( commitmentPoint, lntypes.Remote, chanState.ChanType, - &chanState.LocalChanCfg, &chanState.RemoteChanCfg, + &chanState.ChanCfgs.Local, &chanState.ChanCfgs.Remote, ) // Next, reconstruct the scripts as they were present at this state @@ -2107,7 +2108,7 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64, return l.LocalAuxLeaf }, )(auxResult.AuxLeaves) - theirDelay := uint32(chanState.RemoteChanCfg.CsvDelay) + theirDelay := uint32(chanState.ChanCfgs.Remote.CsvDelay) theirScript, err := CommitScriptToSelf( chanState.ChanType, isRemoteInitiator, keyRing.ToLocalKey, keyRing.RevocationKey, theirDelay, leaseExpiry, localAuxLeaf, @@ -2156,7 +2157,7 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64, // // If our balance exceeds the remote party's dust limit, instantiate // the sign descriptor for our output. - if ourAmt >= int64(chanState.RemoteChanCfg.DustLimit) { + if ourAmt >= int64(chanState.ChanCfgs.Remote.DustLimit) { // As we're about to sweep our own output w/o a delay, we'll // obtain the witness script for the success/delay path. witnessScript, err := ourScript.WitnessScriptForPath( @@ -2168,7 +2169,7 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64, br.LocalOutputSignDesc = &input.SignDescriptor{ SingleTweak: keyRing.LocalCommitKeyTweak, - KeyDesc: chanState.LocalChanCfg.PaymentBasePoint, + KeyDesc: chanState.ChanCfgs.Local.PaymentBasePoint, //nolint:lll WitnessScript: witnessScript, Output: &wire.TxOut{ PkScript: ourScript.PkScript(), @@ -2234,7 +2235,7 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64, // Similarly, if their balance exceeds the remote party's dust limit, // assemble the sign descriptor for their output, which we can sweep. - if theirAmt >= int64(chanState.RemoteChanCfg.DustLimit) { + if theirAmt >= int64(chanState.ChanCfgs.Remote.DustLimit) { // As we're trying to defend the channel against a breach // attempt from the remote party, we want to obain the // revocation witness script here. @@ -2246,7 +2247,7 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64, } br.RemoteOutputSignDesc = &input.SignDescriptor{ - KeyDesc: chanState.LocalChanCfg. + KeyDesc: chanState.ChanCfgs.Local. RevocationBasePoint, DoubleTweak: commitmentSecret, WitnessScript: witnessScript, @@ -2332,7 +2333,7 @@ func createHtlcRetribution(chanState *channeldb.OpenChannel, var emptyRetribution HtlcRetribution - theirDelay := uint32(chanState.RemoteChanCfg.CsvDelay) + theirDelay := uint32(chanState.ChanCfgs.Remote.CsvDelay) isRemoteInitiator := !chanState.IsInitiator // We'll generate the original second level witness script now, as @@ -2390,7 +2391,7 @@ func createHtlcRetribution(chanState *channeldb.OpenChannel, } signDesc := input.SignDescriptor{ - KeyDesc: chanState.LocalChanCfg. + KeyDesc: chanState.ChanCfgs.Local. RevocationBasePoint, DoubleTweak: commitmentSecret, WitnessScript: scriptInfo.WitnessScriptToSign(), @@ -2596,7 +2597,7 @@ func createBreachRetributionLegacy(revokedLog *channeldb.ChannelCommitment, chanState.ChanType, htlc.Incoming, lntypes.Remote, chainfee.SatPerKWeight(revokedLog.FeePerKw), htlc.Amt.ToSatoshis(), - chanState.RemoteChanCfg.DustLimit, + chanState.ChanCfgs.Remote.DustLimit, ) { continue @@ -2752,10 +2753,10 @@ func (lc *LightningChannel) fetchCommitmentView( keyRing *CommitmentKeyRing) (*commitment, error) { commitChain := lc.commitChains.Local - dustLimit := lc.channelState.LocalChanCfg.DustLimit + dustLimit := lc.channelState.ChanCfgs.Local.DustLimit if whoseCommitChain.IsRemote() { commitChain = lc.commitChains.Remote - dustLimit = lc.channelState.RemoteChanCfg.DustLimit + dustLimit = lc.channelState.ChanCfgs.Remote.DustLimit } nextHeight := commitChain.tip().height + 1 @@ -3128,8 +3129,8 @@ func genRemoteHtlcSigJobs(keyRing *CommitmentKeyRing, var ( isRemoteInitiator = !chanState.IsInitiator - localChanCfg = chanState.LocalChanCfg - remoteChanCfg = chanState.RemoteChanCfg + localChanCfg = chanState.ChanCfgs.Local + remoteChanCfg = chanState.ChanCfgs.Remote chanType = chanState.ChanType ) @@ -3757,10 +3758,10 @@ func (lc *LightningChannel) validateCommitmentSanity(theirLogCounter, // If the added HTLCs will decrease the balance, make sure they won't // dip the local and remote balances below the channel reserves. ourReserve := lnwire.NewMSatFromSatoshis( - lc.channelState.LocalChanCfg.ChanReserve, + lc.channelState.ChanCfgs.Local.ChanReserve, ) theirReserve := lnwire.NewMSatFromSatoshis( - lc.channelState.RemoteChanCfg.ChanReserve, + lc.channelState.ChanCfgs.Remote.ChanReserve, ) switch { @@ -3840,7 +3841,7 @@ func (lc *LightningChannel) validateCommitmentSanity(theirLogCounter, // First check that the remote updates won't violate it's channel // constraints. err = validateUpdates( - filteredView.Updates.Remote, &lc.channelState.RemoteChanCfg, + filteredView.Updates.Remote, &lc.channelState.ChanCfgs.Remote, ) if err != nil { return err @@ -3849,7 +3850,7 @@ func (lc *LightningChannel) validateCommitmentSanity(theirLogCounter, // Secondly check that our updates won't violate our channel // constraints. err = validateUpdates( - filteredView.Updates.Local, &lc.channelState.LocalChanCfg, + filteredView.Updates.Local, &lc.channelState.ChanCfgs.Local, ) if err != nil { return err @@ -3959,7 +3960,8 @@ func (lc *LightningChannel) SignNextCommitment( // construct the commitment state. keyRing := DeriveCommitmentKeys( commitPoint, lntypes.Remote, lc.channelState.ChanType, - &lc.channelState.LocalChanCfg, &lc.channelState.RemoteChanCfg, + &lc.channelState.ChanCfgs.Local, + &lc.channelState.ChanCfgs.Remote, ) // Create a new commitment view which will calculate the evaluated @@ -4572,10 +4574,10 @@ func (lc *LightningChannel) computeView(view *HtlcView, lnwire.MilliSatoshi, lntypes.WeightUnit, *HtlcView, error) { commitChain := lc.commitChains.Local - dustLimit := lc.channelState.LocalChanCfg.DustLimit + dustLimit := lc.channelState.ChanCfgs.Local.DustLimit if whoseCommitChain.IsRemote() { commitChain = lc.commitChains.Remote - dustLimit = lc.channelState.RemoteChanCfg.DustLimit + dustLimit = lc.channelState.ChanCfgs.Remote.DustLimit } // Since the fetched htlc view will include all updates added after the @@ -4721,7 +4723,7 @@ func genHtlcSigValidationJobs(chanState *channeldb.OpenChannel, var ( isLocalInitiator = chanState.IsInitiator - localChanCfg = chanState.LocalChanCfg + localChanCfg = chanState.ChanCfgs.Local chanType = chanState.ChanType ) @@ -5151,7 +5153,8 @@ func (lc *LightningChannel) ReceiveNewCommitment(commitSigs *CommitSigs) error { commitPoint := input.ComputeCommitmentPoint(commitSecret[:]) keyRing := DeriveCommitmentKeys( commitPoint, lntypes.Local, lc.channelState.ChanType, - &lc.channelState.LocalChanCfg, &lc.channelState.RemoteChanCfg, + &lc.channelState.ChanCfgs.Local, + &lc.channelState.ChanCfgs.Remote, ) // With the current commitment point re-calculated, construct the new @@ -5283,7 +5286,7 @@ func (lc *LightningChannel) ReceiveNewCommitment(commitSigs *CommitSigs) error { return err } - verifyKey := lc.channelState.RemoteChanCfg.MultiSigKey.PubKey + verifyKey := lc.channelState.ChanCfgs.Remote.MultiSigKey.PubKey cSig, err := commitSigs.CommitSig.ToSignature() if err != nil { @@ -5922,11 +5925,11 @@ func (lc *LightningChannel) GetDustSum(whoseCommit lntypes.ChannelParty, var dustSum lnwire.MilliSatoshi - dustLimit := lc.channelState.LocalChanCfg.DustLimit + dustLimit := lc.channelState.ChanCfgs.Local.DustLimit commit := lc.channelState.LocalCommitment if whoseCommit.IsRemote() { // Calculate dust sum on the remote's commitment. - dustLimit = lc.channelState.RemoteChanCfg.DustLimit + dustLimit = lc.channelState.ChanCfgs.Remote.DustLimit commit = lc.channelState.RemoteCommitment } @@ -5997,8 +6000,8 @@ func (lc *LightningChannel) MayAddOutgoingHtlc(amt lnwire.MilliSatoshi) error { // In absence of a specific amount, we want to use minimum htlc value // for the channel. However certain implementations may set this value // to zero, so we only use this value if it is non-zero. - case lc.channelState.LocalChanCfg.MinHTLC != 0: - mockHtlcAmt = lc.channelState.LocalChanCfg.MinHTLC + case lc.channelState.ChanCfgs.Local.MinHTLC != 0: + mockHtlcAmt = lc.channelState.ChanCfgs.Local.MinHTLC // As a last resort, we just add a non-zero amount. default: @@ -6620,8 +6623,8 @@ func (lc *LightningChannel) getSignedCommitTx() (*wire.MsgTx, error) { inputs := SignedCommitTxInputs{ CommitTx: localCommit.CommitTx, CommitSig: localCommit.CommitSig, - OurKey: lc.channelState.LocalChanCfg.MultiSigKey, - TheirKey: lc.channelState.RemoteChanCfg.MultiSigKey, + OurKey: lc.channelState.ChanCfgs.Local.MultiSigKey, + TheirKey: lc.channelState.ChanCfgs.Remote.MultiSigKey, SignDesc: lc.signDesc, } @@ -6723,7 +6726,7 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, //nolint:funlen commitType := lntypes.Remote keyRing := DeriveCommitmentKeys( commitPoint, commitType, chanState.ChanType, - &chanState.LocalChanCfg, &chanState.RemoteChanCfg, + &chanState.ChanCfgs.Local, &chanState.ChanCfgs.Remote, ) auxResult, err := fn.MapOptionZ( @@ -6753,8 +6756,8 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, //nolint:funlen } htlcResolutions, err := extractHtlcResolutions( chainfee.SatPerKWeight(remoteCommit.FeePerKw), commitType, - signer, remoteCommit.Htlcs, keyRing, &chanState.LocalChanCfg, - &chanState.RemoteChanCfg, commitSpend.SpendingTx, + signer, remoteCommit.Htlcs, keyRing, &chanState.ChanCfgs.Local, + &chanState.ChanCfgs.Remote, commitSpend.SpendingTx, chanState.ChanType, isRemoteInitiator, leaseExpiry, chanState, auxResult.AuxLeaves, auxResolver, ) @@ -6795,7 +6798,7 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, //nolint:funlen // non-trimmed balance. var commitResolution *CommitOutputResolution if selfPoint != nil { - localPayBase := chanState.LocalChanCfg.PaymentBasePoint + localPayBase := chanState.ChanCfgs.Local.PaymentBasePoint // As the remote party has force closed, we just need the // success witness script. @@ -6886,7 +6889,7 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, //nolint:funlen RemoteCurrentRevocation: chanState.RemoteCurrentRevocation, RemoteNextRevocation: chanState.RemoteNextRevocation, ShortChanID: chanState.ShortChanID(), - LocalChanConfig: chanState.LocalChanCfg, + LocalChanConfig: chanState.ChanCfgs.Local, } // Attempt to add a channel sync message to the close summary. @@ -7964,7 +7967,6 @@ func (lc *LightningChannel) ForceClose(opts ...ForceCloseOpt) ( return summary, nil } - // NewLocalForceCloseSummary generates a LocalForceCloseSummary from the given // channel state. The passed commitTx must be a fully signed commitment // transaction corresponding to localCommit. @@ -7978,7 +7980,7 @@ func NewLocalForceCloseSummary(chanState *channeldb.OpenChannel, // commitment transaction. We'll need this to find the corresponding // output in the commitment transaction and potentially for creating // the sign descriptor. - csvTimeout := uint32(chanState.LocalChanCfg.CsvDelay) + csvTimeout := uint32(chanState.ChanCfgs.Local.CsvDelay) // We use the passed state num to derive our scripts, since in case // this is after recovery, our latest channels state might not be up to @@ -7990,7 +7992,7 @@ func NewLocalForceCloseSummary(chanState *channeldb.OpenChannel, commitPoint := input.ComputeCommitmentPoint(revocation[:]) keyRing := DeriveCommitmentKeys( commitPoint, lntypes.Local, chanState.ChanType, - &chanState.LocalChanCfg, &chanState.RemoteChanCfg, + &chanState.ChanCfgs.Local, &chanState.ChanCfgs.Remote, ) auxResult, err := fn.MapOptionZ( @@ -8066,7 +8068,7 @@ func NewLocalForceCloseSummary(chanState *channeldb.OpenChannel, Index: delayIndex, }, SelfOutputSignDesc: input.SignDescriptor{ - KeyDesc: chanState.LocalChanCfg.DelayBasePoint, + KeyDesc: chanState.ChanCfgs.Local.DelayBasePoint, //nolint:lll SingleTweak: keyRing.LocalCommitKeyTweak, WitnessScript: witnessScript, Output: &wire.TxOut{ @@ -8137,8 +8139,8 @@ func NewLocalForceCloseSummary(chanState *channeldb.OpenChannel, localCommit := chanState.LocalCommitment htlcResolutions, err := extractHtlcResolutions( chainfee.SatPerKWeight(localCommit.FeePerKw), lntypes.Local, - signer, localCommit.Htlcs, keyRing, &chanState.LocalChanCfg, - &chanState.RemoteChanCfg, commitTx, chanState.ChanType, + signer, localCommit.Htlcs, keyRing, &chanState.ChanCfgs.Local, + &chanState.ChanCfgs.Remote, commitTx, chanState.ChanType, chanState.IsInitiator, leaseExpiry, chanState, auxResult.AuxLeaves, auxResolver, ) @@ -8286,9 +8288,11 @@ func (lc *LightningChannel) CreateCloseProposal(proposedFee btcutil.Amount, } closeTx, err := CreateCooperativeCloseTx( - fundingTxIn(lc.channelState), lc.channelState.LocalChanCfg.DustLimit, - lc.channelState.RemoteChanCfg.DustLimit, ourBalance, theirBalance, - localDeliveryScript, remoteDeliveryScript, closeTxOpts..., + fundingTxIn(lc.channelState), + lc.channelState.ChanCfgs.Local.DustLimit, + lc.channelState.ChanCfgs.Remote.DustLimit, ourBalance, + theirBalance, localDeliveryScript, remoteDeliveryScript, + closeTxOpts..., ) if err != nil { return nil, nil, 0, err @@ -8390,9 +8394,11 @@ func (lc *LightningChannel) CompleteCooperativeClose( // on this active channel back to both parties. In this current model, // the initiator pays full fees for the cooperative close transaction. closeTx, err := CreateCooperativeCloseTx( - fundingTxIn(lc.channelState), lc.channelState.LocalChanCfg.DustLimit, - lc.channelState.RemoteChanCfg.DustLimit, ourBalance, theirBalance, - localDeliveryScript, remoteDeliveryScript, closeTxOpts..., + fundingTxIn(lc.channelState), + lc.channelState.ChanCfgs.Local.DustLimit, + lc.channelState.ChanCfgs.Remote.DustLimit, ourBalance, + theirBalance, localDeliveryScript, remoteDeliveryScript, + closeTxOpts..., ) if err != nil { return nil, 0, err @@ -8440,9 +8446,9 @@ func (lc *LightningChannel) CompleteCooperativeClose( } else { // For regular channels, we'll need to , construct the witness // stack minding the order of the pubkeys+sigs on the stack. - ourKey := lc.channelState.LocalChanCfg.MultiSigKey.PubKey. + ourKey := lc.channelState.ChanCfgs.Local.MultiSigKey.PubKey. SerializeCompressed() - theirKey := lc.channelState.RemoteChanCfg.MultiSigKey.PubKey. + theirKey := lc.channelState.ChanCfgs.Remote.MultiSigKey.PubKey. SerializeCompressed() witness := input.SpendMultiSig( lc.signDesc.WitnessScript, ourKey, localSig, theirKey, @@ -8510,7 +8516,8 @@ func (lc *LightningChannel) NewAnchorResolutions() (*AnchorResolutions, localCommitPoint := input.ComputeCommitmentPoint(revocation[:]) localKeyRing := DeriveCommitmentKeys( localCommitPoint, lntypes.Local, lc.channelState.ChanType, - &lc.channelState.LocalChanCfg, &lc.channelState.RemoteChanCfg, + &lc.channelState.ChanCfgs.Local, + &lc.channelState.ChanCfgs.Remote, ) localRes, err := NewAnchorResolution( lc.channelState, lc.channelState.LocalCommitment.CommitTx, @@ -8524,8 +8531,8 @@ func (lc *LightningChannel) NewAnchorResolutions() (*AnchorResolutions, // Add anchor for remote commitment tx, if any. remoteKeyRing := DeriveCommitmentKeys( lc.channelState.RemoteCurrentRevocation, lntypes.Remote, - lc.channelState.ChanType, &lc.channelState.LocalChanCfg, - &lc.channelState.RemoteChanCfg, + lc.channelState.ChanType, &lc.channelState.ChanCfgs.Local, + &lc.channelState.ChanCfgs.Remote, ) remoteRes, err := NewAnchorResolution( lc.channelState, lc.channelState.RemoteCommitment.CommitTx, @@ -8545,8 +8552,9 @@ func (lc *LightningChannel) NewAnchorResolutions() (*AnchorResolutions, if remotePendingCommit != nil { pendingRemoteKeyRing := DeriveCommitmentKeys( lc.channelState.RemoteNextRevocation, lntypes.Remote, - lc.channelState.ChanType, &lc.channelState.LocalChanCfg, - &lc.channelState.RemoteChanCfg, + lc.channelState.ChanType, + &lc.channelState.ChanCfgs.Local, + &lc.channelState.ChanCfgs.Remote, ) remotePendingRes, err := NewAnchorResolution( lc.channelState, @@ -8578,8 +8586,8 @@ func NewAnchorResolution(chanState *channeldb.OpenChannel, // will differ depending on if this is our local or remote // commitment. localAnchor, remoteAnchor, err := CommitScriptAnchors( - chanState.ChanType, &chanState.LocalChanCfg, - &chanState.RemoteChanCfg, keyRing, + chanState.ChanType, &chanState.ChanCfgs.Local, + &chanState.ChanCfgs.Remote, keyRing, ) if err != nil { return nil, err @@ -8616,7 +8624,7 @@ func NewAnchorResolution(chanState *channeldb.OpenChannel, // Instantiate the sign descriptor that allows sweeping of the anchor. signDesc := &input.SignDescriptor{ - KeyDesc: chanState.LocalChanCfg.MultiSigKey, + KeyDesc: chanState.ChanCfgs.Local.MultiSigKey, WitnessScript: anchorWitnessScript, Output: &wire.TxOut{ PkScript: localAnchor.PkScript(), @@ -8646,14 +8654,15 @@ func NewAnchorResolution(chanState *channeldb.OpenChannel, // tweak. signDesc.SingleTweak = keyRing.LocalCommitKeyTweak - signDesc.KeyDesc = chanState.LocalChanCfg.DelayBasePoint + signDesc.KeyDesc = + chanState.ChanCfgs.Local.DelayBasePoint } else { // When we're playing the force close of a remote // commitment, as this is a "tweakless" channel type, // we don't need a tweak value at all. // //nolint:lll - signDesc.KeyDesc = chanState.LocalChanCfg.PaymentBasePoint + signDesc.KeyDesc = chanState.ChanCfgs.Local.PaymentBasePoint } // Finally, as this is a keyspend method, we'll need to also @@ -8767,7 +8776,7 @@ func (lc *LightningChannel) availableCommitmentBalance(view *HtlcView, // We can never spend from the channel reserve, so we'll subtract it // from our available balance. ourReserve := lnwire.NewMSatFromSatoshis( - lc.channelState.LocalChanCfg.ChanReserve, + lc.channelState.ChanCfgs.Local.ChanReserve, ) if ourReserve <= ourBalance { ourBalance -= ourReserve @@ -8820,7 +8829,7 @@ func (lc *LightningChannel) availableCommitmentBalance(view *HtlcView, // enough balance to pay for the fee of our HTLC. We'll start by also // subtracting our counterparty's reserve from their balance. theirReserve := lnwire.NewMSatFromSatoshis( - lc.channelState.RemoteChanCfg.ChanReserve, + lc.channelState.ChanCfgs.Remote.ChanReserve, ) if theirReserve <= theirBalance { theirBalance -= theirReserve @@ -8831,7 +8840,7 @@ func (lc *LightningChannel) availableCommitmentBalance(view *HtlcView, // We'll use the dustlimit and htlcFee to find the largest HTLC value // that will be considered dust on the commitment. dustlimit := lnwire.NewMSatFromSatoshis( - lc.channelState.LocalChanCfg.DustLimit, + lc.channelState.ChanCfgs.Local.DustLimit, ) // For an extra HTLC fee to be paid on our commitment, the HTLC must be @@ -8844,7 +8853,7 @@ func (lc *LightningChannel) availableCommitmentBalance(view *HtlcView, // dust limit and the fee for adding an HTLC success transaction. if whoseCommitChain.IsRemote() { dustlimit = lnwire.NewMSatFromSatoshis( - lc.channelState.RemoteChanCfg.DustLimit, + lc.channelState.ChanCfgs.Remote.DustLimit, ) htlcFee = lnwire.NewMSatFromSatoshis( HtlcSuccessFee(lc.channelState.ChanType, feePerKw), @@ -9073,7 +9082,7 @@ func (lc *LightningChannel) generateRevocation(height uint64) (*lnwire.RevokeAnd // verification nonce for this target state. if lc.channelState.ChanType.IsTaproot() { nextVerificationNonce, err := channeldb.NewMusigVerificationNonce( //nolint:lll - lc.channelState.LocalChanCfg.MultiSigKey.PubKey, + lc.channelState.ChanCfgs.Local.MultiSigKey.PubKey, revHeight, lc.taprootNonceProducer, ) if err != nil { @@ -9308,7 +9317,7 @@ func (lc *LightningChannel) LocalBalanceDust() (bool, btcutil.Amount) { localBalance += 2 * AnchorSize } - localDust := chanState.LocalChanCfg.DustLimit + localDust := chanState.ChanCfgs.Local.DustLimit return localBalance <= localDust, localDust } @@ -9330,7 +9339,7 @@ func (lc *LightningChannel) RemoteBalanceDust() (bool, btcutil.Amount) { remoteBalance += 2 * AnchorSize } - remoteDust := chanState.RemoteChanCfg.DustLimit + remoteDust := chanState.ChanCfgs.Remote.DustLimit return remoteBalance <= remoteDust, remoteDust } @@ -9379,8 +9388,8 @@ func (lc *LightningChannel) CalcFee(feeRate chainfee.SatPerKWeight) btcutil.Amou // Moreover it returns the share of the total balance in the range of [0,1] // which can be allocated to fees. When our desired fee allocation would lead to // a maximum fee rate below the current commitment fee rate we floor the maximum -// at the current fee rate which leads to different fee allocations than -// initially requested via `maxAllocation`. +// fee rate at the current fee rate which leads to different fee allocations +// than initially requested via `maxAllocation`. // // NOTE: This should only be used for channels in which the local commitment is // the initiator. @@ -9623,7 +9632,7 @@ func (lc *LightningChannel) ActiveHtlcs() []channeldb.HTLC { // LocalChanReserve returns our local ChanReserve requirement for the remote party. func (lc *LightningChannel) LocalChanReserve() btcutil.Amount { - return lc.channelState.LocalChanCfg.ChanReserve + return lc.channelState.ChanCfgs.Local.ChanReserve } // NextLocalHtlcIndex returns the next unallocated local htlc index. To ensure @@ -9640,7 +9649,7 @@ func (lc *LightningChannel) NextLocalHtlcIndex() (uint64, error) { // FwdMinHtlc returns the minimum HTLC value required by the remote node, i.e. // the minimum value HTLC we can forward on this channel. func (lc *LightningChannel) FwdMinHtlc() lnwire.MilliSatoshi { - return lc.channelState.LocalChanCfg.MinHTLC + return lc.channelState.ChanCfgs.Local.MinHTLC } // unsignedLocalUpdates retrieves the unsigned local updates that we should @@ -9693,7 +9702,7 @@ func (lc *LightningChannel) GenMusigNonces() (*musig2.Nonces, error) { // verification nonces we'll send to the party to create our _next_ // state. lc.pendingVerificationNonce, err = channeldb.NewMusigVerificationNonce( - lc.channelState.LocalChanCfg.MultiSigKey.PubKey, + lc.channelState.ChanCfgs.Local.MultiSigKey.PubKey, lc.currentHeight+1, lc.taprootNonceProducer, ) if err != nil { @@ -9727,8 +9736,8 @@ func (lc *LightningChannel) InitRemoteMusigNonces(remoteNonce *musig2.Nonces, // commitment of the remote party. localNonce := lc.pendingVerificationNonce - localChanCfg := lc.channelState.LocalChanCfg - remoteChanCfg := lc.channelState.RemoteChanCfg + localChanCfg := lc.channelState.ChanCfgs.Local + remoteChanCfg := lc.channelState.ChanCfgs.Remote // TODO(roasbeef): propagate rename of signing and verification nonces @@ -9784,8 +9793,8 @@ func (lc *LightningChannel) MultiSigKeys() (keychain.KeyDescriptor, lc.RLock() defer lc.RUnlock() - return lc.channelState.LocalChanCfg.MultiSigKey, - lc.channelState.RemoteChanCfg.MultiSigKey + return lc.channelState.ChanCfgs.Local.MultiSigKey, + lc.channelState.ChanCfgs.Remote.MultiSigKey } // LocalCommitmentBlob returns the custom blob of the local commitment. diff --git a/lnwallet/channel_test.go b/lnwallet/channel_test.go index 8fc3d8b4681..d56c670c842 100644 --- a/lnwallet/channel_test.go +++ b/lnwallet/channel_test.go @@ -1019,7 +1019,8 @@ func testForceClose(t *testing.T, testCase *forceCloseTestCase) { } // The rest of the close summary should have been populated properly. - aliceDelayPoint := aliceChannel.channelState.LocalChanCfg.DelayBasePoint + aliceDelayPoint := + aliceChannel.channelState.ChanCfgs.Local.DelayBasePoint if !aliceCommitResolution.SelfOutputSignDesc.KeyDesc.PubKey.IsEqual( aliceDelayPoint.PubKey, ) { @@ -1047,11 +1048,11 @@ func testForceClose(t *testing.T, testCase *forceCloseTestCase) { // Alice's listed CSV delay should also match the delay that was // pre-committed to at channel opening. if aliceCommitResolution.MaturityDelay != - uint32(aliceChannel.channelState.LocalChanCfg.CsvDelay) { + uint32(aliceChannel.channelState.ChanCfgs.Local.CsvDelay) { t.Fatalf("alice: incorrect local CSV delay in ForceCloseSummary, "+ "expected %v, got %v", - aliceChannel.channelState.LocalChanCfg.CsvDelay, + aliceChannel.channelState.ChanCfgs.Local.CsvDelay, aliceCommitResolution.MaturityDelay) } @@ -1095,7 +1096,7 @@ func testForceClose(t *testing.T, testCase *forceCloseTestCase) { }) htlcResolution.SweepSignDesc.InputIndex = 0 - csvDelay := uint32(aliceChannel.channelState.LocalChanCfg.CsvDelay) + csvDelay := uint32(aliceChannel.channelState.ChanCfgs.Local.CsvDelay) if testCase.chanType.IsTaproot() { sweepTx.TxIn[0].Sequence = input.LockTimeToSequence( false, csvDelay, @@ -1197,7 +1198,8 @@ func testForceClose(t *testing.T, testCase *forceCloseTestCase) { sweepTx.TxIn[0].Witness, err = input.HtlcSpendSuccess( aliceChannel.Signer, &inHtlcResolution.SweepSignDesc, sweepTx, - uint32(aliceChannel.channelState.LocalChanCfg.CsvDelay), + //nolint:lll + uint32(aliceChannel.channelState.ChanCfgs.Local.CsvDelay), ) } require.NoError(t, err, "unable to gen witness for timeout output") @@ -1228,7 +1230,7 @@ func testForceClose(t *testing.T, testCase *forceCloseTestCase) { if bobCommitResolution == nil { t.Fatalf("bob fails to include to-self output in ForceCloseSummary") } - bobDelayPoint := bobChannel.channelState.LocalChanCfg.DelayBasePoint + bobDelayPoint := bobChannel.channelState.ChanCfgs.Local.DelayBasePoint if !bobCommitResolution.SelfOutputSignDesc.KeyDesc.PubKey.IsEqual(bobDelayPoint.PubKey) { t.Fatalf("bob incorrect pubkey in SelfOutputSignDesc") } @@ -1241,11 +1243,11 @@ func testForceClose(t *testing.T, testCase *forceCloseTestCase) { int64(bobCommitResolution.SelfOutputSignDesc.Output.Value)) } if bobCommitResolution.MaturityDelay != - uint32(bobChannel.channelState.LocalChanCfg.CsvDelay) { + uint32(bobChannel.channelState.ChanCfgs.Local.CsvDelay) { t.Fatalf("bob: incorrect local CSV delay in ForceCloseSummary, "+ "expected %v, got %v", - bobChannel.channelState.LocalChanCfg.CsvDelay, + bobChannel.channelState.ChanCfgs.Local.CsvDelay, bobCommitResolution.MaturityDelay) } @@ -1291,10 +1293,10 @@ func TestForceCloseDustOutput(t *testing.T) { // We set both node's channel reserves to 0, to make sure // they can create small dust outputs without going under // their channel reserves. - aliceChannel.channelState.LocalChanCfg.ChanReserve = 0 - bobChannel.channelState.LocalChanCfg.ChanReserve = 0 - aliceChannel.channelState.RemoteChanCfg.ChanReserve = 0 - bobChannel.channelState.RemoteChanCfg.ChanReserve = 0 + aliceChannel.channelState.ChanCfgs.Local.ChanReserve = 0 + bobChannel.channelState.ChanCfgs.Local.ChanReserve = 0 + aliceChannel.channelState.ChanCfgs.Remote.ChanReserve = 0 + bobChannel.channelState.ChanCfgs.Remote.ChanReserve = 0 htlcAmount := lnwire.NewMSatFromSatoshis(500) @@ -1339,7 +1341,7 @@ func TestForceCloseDustOutput(t *testing.T) { "ForceCloseSummary") } if !commitResolution.SelfOutputSignDesc.KeyDesc.PubKey.IsEqual( - aliceChannel.channelState.LocalChanCfg.DelayBasePoint.PubKey, + aliceChannel.channelState.ChanCfgs.Local.DelayBasePoint.PubKey, ) { t.Fatalf("alice incorrect pubkey in SelfOutputSignDesc") } @@ -1352,10 +1354,11 @@ func TestForceCloseDustOutput(t *testing.T) { } if commitResolution.MaturityDelay != - uint32(aliceChannel.channelState.LocalChanCfg.CsvDelay) { + uint32(aliceChannel.channelState.ChanCfgs.Local.CsvDelay) { + t.Fatalf("alice: incorrect local CSV delay in ForceCloseSummary, "+ "expected %v, got %v", - aliceChannel.channelState.LocalChanCfg.CsvDelay, + aliceChannel.channelState.ChanCfgs.Local.CsvDelay, commitResolution.MaturityDelay) } @@ -1707,8 +1710,8 @@ func TestChannelBalanceDustLimit(t *testing.T) { // To allow Alice's balance to get beneath her dust limit, set the // channel reserve to be 0. - aliceChannel.channelState.LocalChanCfg.ChanReserve = 0 - bobChannel.channelState.RemoteChanCfg.ChanReserve = 0 + aliceChannel.channelState.ChanCfgs.Local.ChanReserve = 0 + bobChannel.channelState.ChanCfgs.Remote.ChanReserve = 0 // This amount should leave an amount larger than Alice's dust limit // once fees have been subtracted, but smaller than Bob's dust limit. @@ -2220,10 +2223,10 @@ func TestCooperativeCloseDustAdherence(t *testing.T) { ) setDustLimit := func(dustVal btcutil.Amount) { - aliceChannel.channelState.LocalChanCfg.DustLimit = dustVal - aliceChannel.channelState.RemoteChanCfg.DustLimit = dustVal - bobChannel.channelState.LocalChanCfg.DustLimit = dustVal - bobChannel.channelState.RemoteChanCfg.DustLimit = dustVal + aliceChannel.channelState.ChanCfgs.Local.DustLimit = dustVal + aliceChannel.channelState.ChanCfgs.Remote.DustLimit = dustVal + bobChannel.channelState.ChanCfgs.Local.DustLimit = dustVal + bobChannel.channelState.ChanCfgs.Remote.DustLimit = dustVal } resetChannelState := func() { @@ -2896,7 +2899,7 @@ func TestAddHTLCNegativeBalance(t *testing.T) { // We set the channel reserve to 0, such that we can add HTLCs all the // way to a negative balance. - aliceChannel.channelState.LocalChanCfg.ChanReserve = 0 + aliceChannel.channelState.ChanCfgs.Local.ChanReserve = 0 // First, we'll add 3 HTLCs of 1 BTC each to Alice's commitment. const numHTLCs = 3 @@ -5230,7 +5233,7 @@ func TestChanAvailableBandwidth(t *testing.T) { require.NoError(t, err, "unable to create test channels") aliceReserve := lnwire.NewMSatFromSatoshis( - aliceChannel.channelState.LocalChanCfg.ChanReserve, + aliceChannel.channelState.ChanCfgs.Local.ChanReserve, ) feeRate := chainfee.SatPerKWeight( aliceChannel.channelState.LocalCommitment.FeePerKw, @@ -5366,14 +5369,14 @@ func TestChanAvailableBalanceNearHtlcFee(t *testing.T) { bobBalance := lnwire.NewMSatFromSatoshis(5 * btcutil.SatoshiPerBitcoin) aliceReserve := lnwire.NewMSatFromSatoshis( - aliceChannel.channelState.LocalChanCfg.ChanReserve, + aliceChannel.channelState.ChanCfgs.Local.ChanReserve, ) bobReserve := lnwire.NewMSatFromSatoshis( - bobChannel.channelState.LocalChanCfg.ChanReserve, + bobChannel.channelState.ChanCfgs.Local.ChanReserve, ) aliceDustlimit := lnwire.NewMSatFromSatoshis( - aliceChannel.channelState.LocalChanCfg.DustLimit, + aliceChannel.channelState.ChanCfgs.Local.DustLimit, ) feeRate := chainfee.SatPerKWeight( aliceChannel.channelState.LocalCommitment.FeePerKw, @@ -5553,10 +5556,10 @@ func TestChanCommitWeightDustHtlcs(t *testing.T) { require.NoError(t, err, "unable to create test channels") aliceDustlimit := lnwire.NewMSatFromSatoshis( - aliceChannel.channelState.LocalChanCfg.DustLimit, + aliceChannel.channelState.ChanCfgs.Local.DustLimit, ) bobDustlimit := lnwire.NewMSatFromSatoshis( - bobChannel.channelState.LocalChanCfg.DustLimit, + bobChannel.channelState.ChanCfgs.Local.DustLimit, ) feeRate := chainfee.SatPerKWeight( @@ -6388,14 +6391,14 @@ func TestMaxAcceptedHTLCs(t *testing.T) { // Set the remote's required MaxAcceptedHtlcs. This means that Alice // can only offer the remote up to numHTLCs HTLCs. - aliceChannel.channelState.LocalChanCfg.MaxAcceptedHtlcs = numHTLCs - bobChannel.channelState.RemoteChanCfg.MaxAcceptedHtlcs = numHTLCs + aliceChannel.channelState.ChanCfgs.Local.MaxAcceptedHtlcs = numHTLCs + bobChannel.channelState.ChanCfgs.Remote.MaxAcceptedHtlcs = numHTLCs // Similarly, set the remote config's MaxAcceptedHtlcs. This means // that the remote will be aware that Bob will only accept up to // numHTLCs at a time. - aliceChannel.channelState.RemoteChanCfg.MaxAcceptedHtlcs = numHTLCs - bobChannel.channelState.LocalChanCfg.MaxAcceptedHtlcs = numHTLCs + aliceChannel.channelState.ChanCfgs.Remote.MaxAcceptedHtlcs = numHTLCs + bobChannel.channelState.ChanCfgs.Local.MaxAcceptedHtlcs = numHTLCs // Each HTLC amount is 0.1 BTC. htlcAmt := lnwire.NewMSatFromSatoshis(0.1 * btcutil.SatoshiPerBitcoin) @@ -6505,14 +6508,14 @@ func TestMaxAsynchronousHtlcs(t *testing.T) { // Set the remote's required MaxAcceptedHtlcs. This means that Alice // can only offer the remote up to numHTLCs HTLCs. - aliceChannel.channelState.LocalChanCfg.MaxAcceptedHtlcs = numHTLCs - bobChannel.channelState.RemoteChanCfg.MaxAcceptedHtlcs = numHTLCs + aliceChannel.channelState.ChanCfgs.Local.MaxAcceptedHtlcs = numHTLCs + bobChannel.channelState.ChanCfgs.Remote.MaxAcceptedHtlcs = numHTLCs // Similarly, set the remote config's MaxAcceptedHtlcs. This means // that the remote will be aware that Bob will only accept up to // numHTLCs at a time. - aliceChannel.channelState.RemoteChanCfg.MaxAcceptedHtlcs = numHTLCs - bobChannel.channelState.LocalChanCfg.MaxAcceptedHtlcs = numHTLCs + aliceChannel.channelState.ChanCfgs.Remote.MaxAcceptedHtlcs = numHTLCs + bobChannel.channelState.ChanCfgs.Local.MaxAcceptedHtlcs = numHTLCs // Each HTLC amount is 0.1 BTC. htlcAmt := lnwire.NewMSatFromSatoshis(0.1 * btcutil.SatoshiPerBitcoin) @@ -6605,8 +6608,8 @@ func TestMaxPendingAmount(t *testing.T) { // We set the max pending amount of Alice's config. This mean that she // cannot offer Bob HTLCs with a total value above this limit at a given // time. - aliceChannel.channelState.LocalChanCfg.MaxPendingAmount = maxPending - bobChannel.channelState.RemoteChanCfg.MaxPendingAmount = maxPending + aliceChannel.channelState.ChanCfgs.Local.MaxPendingAmount = maxPending + bobChannel.channelState.ChanCfgs.Remote.MaxPendingAmount = maxPending // First, we'll add 2 HTLCs of 1.5 BTC each to Alice's commitment. // This won't trigger Alice's ErrMaxPendingAmount error. @@ -6684,20 +6687,24 @@ func TestChanReserve(t *testing.T) { // Alice will need to keep her reserve above aliceMinReserve, // so set this limit to here local config. - aliceChannel.channelState.LocalChanCfg.ChanReserve = aliceMinReserve + aliceChannel.channelState.ChanCfgs.Local.ChanReserve = + aliceMinReserve // During channel opening Bob will also get to know Alice's // minimum reserve, and this will be found in his remote // config. - bobChannel.channelState.RemoteChanCfg.ChanReserve = aliceMinReserve + bobChannel.channelState.ChanCfgs.Remote.ChanReserve = + aliceMinReserve // We set Bob's channel reserve to a value that is larger than // his current balance in the channel. This will ensure that // after a channel is first opened, Bob can still receive HTLCs // even though his balance is less than his channel reserve. bobMinReserve := btcutil.Amount(6 * btcutil.SatoshiPerBitcoin) - bobChannel.channelState.LocalChanCfg.ChanReserve = bobMinReserve - aliceChannel.channelState.RemoteChanCfg.ChanReserve = bobMinReserve + bobChannel.channelState.ChanCfgs.Local.ChanReserve = + bobMinReserve + aliceChannel.channelState.ChanCfgs.Remote.ChanReserve = + bobMinReserve return aliceChannel, bobChannel } @@ -6865,8 +6872,8 @@ func TestChanReserveRemoteInitiator(t *testing.T) { commitFee := aliceChannel.channelState.LocalCommitment.CommitFee aliceMinReserve := 5*btcutil.SatoshiPerBitcoin - commitFee - aliceChannel.channelState.LocalChanCfg.ChanReserve = aliceMinReserve - bobChannel.channelState.RemoteChanCfg.ChanReserve = aliceMinReserve + aliceChannel.channelState.ChanCfgs.Local.ChanReserve = aliceMinReserve + bobChannel.channelState.ChanCfgs.Remote.ChanReserve = aliceMinReserve // Now let Bob attempt to add an HTLC of 0.1 BTC. He has plenty of // money available to spend, but Alice, which is the initiator, cannot @@ -6920,8 +6927,8 @@ func TestChanReserveLocalInitiatorDustHtlc(t *testing.T) { commitFee := aliceChannel.channelState.LocalCommitment.CommitFee aliceMinReserve := 5*btcutil.SatoshiPerBitcoin - commitFee - htlcSat - aliceChannel.channelState.LocalChanCfg.ChanReserve = aliceMinReserve - bobChannel.channelState.RemoteChanCfg.ChanReserve = aliceMinReserve + aliceChannel.channelState.ChanCfgs.Local.ChanReserve = aliceMinReserve + bobChannel.channelState.ChanCfgs.Remote.ChanReserve = aliceMinReserve htlcDustAmt := lnwire.NewMSatFromSatoshis(htlcSat) htlc, _ := createHTLC(0, htlcDustAmt) @@ -6950,8 +6957,8 @@ func TestMinHTLC(t *testing.T) { // Setting the min value in Alice's local config means that the // remote will not accept any HTLCs of value less than specified. - aliceChannel.channelState.LocalChanCfg.MinHTLC = minValue - bobChannel.channelState.RemoteChanCfg.MinHTLC = minValue + aliceChannel.channelState.ChanCfgs.Local.MinHTLC = minValue + bobChannel.channelState.ChanCfgs.Remote.MinHTLC = minValue // First, we will add an HTLC of 0.5 BTC. This will not trigger // ErrBelowMinHTLC. @@ -6990,8 +6997,8 @@ func TestInvalidHTLCAmt(t *testing.T) { // We'll set the min HTLC values for each party to zero, which // technically would permit zero-value HTLCs. - aliceChannel.channelState.LocalChanCfg.MinHTLC = 0 - bobChannel.channelState.RemoteChanCfg.MinHTLC = 0 + aliceChannel.channelState.ChanCfgs.Local.MinHTLC = 0 + bobChannel.channelState.ChanCfgs.Remote.MinHTLC = 0 // Create a zero-value HTLC. htlcAmt := lnwire.MilliSatoshi(0) @@ -7029,10 +7036,10 @@ func TestNewBreachRetributionSkipsDustHtlcs(t *testing.T) { // We'll modify the dust settings on both channels to be a predictable // value for the prurpose of the test. dustValue := btcutil.Amount(200) - aliceChannel.channelState.LocalChanCfg.DustLimit = dustValue - aliceChannel.channelState.RemoteChanCfg.DustLimit = dustValue - bobChannel.channelState.LocalChanCfg.DustLimit = dustValue - bobChannel.channelState.RemoteChanCfg.DustLimit = dustValue + aliceChannel.channelState.ChanCfgs.Local.DustLimit = dustValue + aliceChannel.channelState.ChanCfgs.Remote.DustLimit = dustValue + bobChannel.channelState.ChanCfgs.Local.DustLimit = dustValue + bobChannel.channelState.ChanCfgs.Remote.DustLimit = dustValue // We'll now create a series of dust HTLC's, and send then from Alice // to Bob, finally locking both of them in. @@ -9362,7 +9369,7 @@ func TestMayAddOutgoingHtlc(t *testing.T) { // Hard set alice's min htlc to zero and test the case where we just // fall back to a non-zero value. - aliceChannel.channelState.LocalChanCfg.MinHTLC = 0 + aliceChannel.channelState.ChanCfgs.Local.MinHTLC = 0 require.NoError(t, aliceChannel.MayAddOutgoingHtlc(0)) } @@ -9683,12 +9690,12 @@ func testGetDustSum(t *testing.T, chantype channeldb.ChannelType) { func deriveDummyRetributionParams(chanState *channeldb.OpenChannel) (uint32, *CommitmentKeyRing, chainhash.Hash) { - config := chanState.RemoteChanCfg + config := chanState.ChanCfgs.Remote commitHash := chanState.RemoteCommitment.CommitTx.TxHash() keyRing := DeriveCommitmentKeys( config.RevocationBasePoint.PubKey, lntypes.Remote, - chanState.ChanType, &chanState.LocalChanCfg, - &chanState.RemoteChanCfg, + chanState.ChanType, &chanState.ChanCfgs.Local, + &chanState.ChanCfgs.Remote, ) leaseExpiry := chanState.ThawHeight return leaseExpiry, keyRing, commitHash @@ -10044,7 +10051,7 @@ func testNewBreachRetribution(t *testing.T, chanType channeldb.ChannelType) { breachHeight := uint32(101) stateNum := uint64(0) chainHash := aliceChannel.channelState.ChainHash - theirDelay := uint32(aliceChannel.channelState.RemoteChanCfg.CsvDelay) + theirDelay := uint32(aliceChannel.channelState.ChanCfgs.Remote.CsvDelay) breachTx := aliceChannel.channelState.RemoteCommitment.CommitTx // Create a breach retribution at height 0, which should give us an @@ -10405,7 +10412,7 @@ func TestAsynchronousSendingContraint(t *testing.T) { ) require.NoError(t, err) - aliceReserve := aliceChannel.channelState.LocalChanCfg.ChanReserve + aliceReserve := aliceChannel.channelState.ChanCfgs.Local.ChanReserve capacity := aliceChannel.channelState.Capacity @@ -10440,7 +10447,7 @@ func TestAsynchronousSendingContraint(t *testing.T) { // We need to take the remote dustlimit amount, because it the greater // one. htlcAmt2 := lnwire.NewMSatFromSatoshis( - aliceChannel.channelState.RemoteChanCfg.DustLimit + htlcFee, + aliceChannel.channelState.ChanCfgs.Remote.DustLimit + htlcFee, ) htlc2, _ := createHTLC(0, htlcAmt2) @@ -10538,7 +10545,7 @@ func TestAsynchronousSendingWithFeeBuffer(t *testing.T) { ) require.NoError(t, err) - aliceReserve := aliceChannel.channelState.LocalChanCfg.ChanReserve + aliceReserve := aliceChannel.channelState.ChanCfgs.Local.ChanReserve capacity := aliceChannel.channelState.Capacity @@ -10572,7 +10579,7 @@ func TestAsynchronousSendingWithFeeBuffer(t *testing.T) { // make sure this htlc is non-dust for alice. htlcFee := HtlcSuccessFee(channeldb.SingleFunderTweaklessBit, feePerKw) htlcAmt2 := lnwire.NewMSatFromSatoshis( - aliceChannel.channelState.LocalChanCfg.DustLimit + htlcFee, + aliceChannel.channelState.ChanCfgs.Local.DustLimit + htlcFee, ) htlc2, _ := createHTLC(0, htlcAmt2) _, err = bobChannel.AddHTLC(htlc2, nil) @@ -10656,7 +10663,7 @@ func TestAsynchronousSendingWithFeeBuffer(t *testing.T) { // Update the non-dust amount because we updated the fee by 100%. htlcFee = HtlcSuccessFee(channeldb.SingleFunderTweaklessBit, feePerKw*2) htlcAmt3 := lnwire.NewMSatFromSatoshis( - aliceChannel.channelState.LocalChanCfg.DustLimit + htlcFee, + aliceChannel.channelState.ChanCfgs.Local.DustLimit + htlcFee, ) htlc3, _ := createHTLC(1, htlcAmt3) addAndReceiveHTLC(t, bobChannel, aliceChannel, htlc3, nil) @@ -10729,7 +10736,7 @@ func TestEnforceFeeBuffer(t *testing.T) { ) require.NoError(t, err) - aliceReserve := aliceChannel.channelState.LocalChanCfg.ChanReserve + aliceReserve := aliceChannel.channelState.ChanCfgs.Local.ChanReserve capacity := aliceChannel.channelState.Capacity diff --git a/lnwallet/commitment.go b/lnwallet/commitment.go index 36ff75edeb4..59d9bf54ba1 100644 --- a/lnwallet/commitment.go +++ b/lnwallet/commitment.go @@ -649,14 +649,14 @@ func NewCommitmentBuilder(chanState *channeldb.OpenChannel, func createStateHintObfuscator(state *channeldb.OpenChannel) [StateHintSize]byte { if state.IsInitiator { return DeriveStateHintObfuscator( - state.LocalChanCfg.PaymentBasePoint.PubKey, - state.RemoteChanCfg.PaymentBasePoint.PubKey, + state.ChanCfgs.Local.PaymentBasePoint.PubKey, + state.ChanCfgs.Remote.PaymentBasePoint.PubKey, ) } return DeriveStateHintObfuscator( - state.RemoteChanCfg.PaymentBasePoint.PubKey, - state.LocalChanCfg.PaymentBasePoint.PubKey, + state.ChanCfgs.Remote.PaymentBasePoint.PubKey, + state.ChanCfgs.Local.PaymentBasePoint.PubKey, ) } @@ -696,9 +696,9 @@ func (cb *CommitmentBuilder) createUnsignedCommitmentTx(ourBalance, filteredHTLCView *HtlcView, keyRing *CommitmentKeyRing, prevCommit *commitment) (*unsignedCommitmentTx, error) { - dustLimit := cb.chanState.LocalChanCfg.DustLimit + dustLimit := cb.chanState.ChanCfgs.Local.DustLimit if whoseCommit.IsRemote() { - dustLimit = cb.chanState.RemoteChanCfg.DustLimit + dustLimit = cb.chanState.ChanCfgs.Remote.DustLimit } numHTLCs := int64(0) @@ -785,7 +785,8 @@ func (cb *CommitmentBuilder) createUnsignedCommitmentTx(ourBalance, if whoseCommit.IsLocal() { commitTx, err = CreateCommitTx( cb.chanState.ChanType, fundingTxIn(cb.chanState), keyRing, - &cb.chanState.LocalChanCfg, &cb.chanState.RemoteChanCfg, + &cb.chanState.ChanCfgs.Local, + &cb.chanState.ChanCfgs.Remote, ourBalance.ToSatoshis(), theirBalance.ToSatoshis(), numHTLCs, cb.chanState.IsInitiator, leaseExpiry, auxResult.AuxLeaves, @@ -793,7 +794,8 @@ func (cb *CommitmentBuilder) createUnsignedCommitmentTx(ourBalance, } else { commitTx, err = CreateCommitTx( cb.chanState.ChanType, fundingTxIn(cb.chanState), keyRing, - &cb.chanState.RemoteChanCfg, &cb.chanState.LocalChanCfg, + &cb.chanState.ChanCfgs.Remote, + &cb.chanState.ChanCfgs.Local, theirBalance.ToSatoshis(), ourBalance.ToSatoshis(), numHTLCs, !cb.chanState.IsInitiator, leaseExpiry, auxResult.AuxLeaves, @@ -1284,13 +1286,13 @@ func findOutputIndexesFromRemote(revocationPreimage *chainhash.Hash, // which will be used to generate the output scripts. keyRing := DeriveCommitmentKeys( commitmentPoint, lntypes.Remote, chanState.ChanType, - &chanState.LocalChanCfg, &chanState.RemoteChanCfg, + &chanState.ChanCfgs.Local, &chanState.ChanCfgs.Remote, ) // Since it's remote commitment chain, we'd used the mirrored values. // // We use the remote's channel config for the csv delay. - theirDelay := uint32(chanState.RemoteChanCfg.CsvDelay) + theirDelay := uint32(chanState.ChanCfgs.Remote.CsvDelay) // If we are the initiator of this channel, then it's be false from the // remote's PoV. diff --git a/lnwallet/test_utils.go b/lnwallet/test_utils.go index 2253232962a..91d81623bf1 100644 --- a/lnwallet/test_utils.go +++ b/lnwallet/test_utils.go @@ -322,8 +322,10 @@ func CreateTestChannels(t *testing.T, chanType channeldb.ChannelType, ) aliceChannelState := &channeldb.OpenChannel{ - LocalChanCfg: aliceCfg, - RemoteChanCfg: bobCfg, + ChanCfgs: lntypes.Dual[channeldb.ChannelConfig]{ + Local: aliceCfg, + Remote: bobCfg, + }, IdentityPub: aliceKeys[0].PubKey(), FundingOutpoint: *prevOut, ShortChannelID: shortChanID, @@ -340,8 +342,10 @@ func CreateTestChannels(t *testing.T, chanType channeldb.ChannelType, FundingTxn: testTx, } bobChannelState := &channeldb.OpenChannel{ - LocalChanCfg: bobCfg, - RemoteChanCfg: aliceCfg, + ChanCfgs: lntypes.Dual[channeldb.ChannelConfig]{ + Local: bobCfg, + Remote: aliceCfg, + }, IdentityPub: bobKeys[0].PubKey(), FundingOutpoint: *prevOut, ShortChannelID: shortChanID, diff --git a/lnwallet/transactions_test.go b/lnwallet/transactions_test.go index 7912772962b..847ed159490 100644 --- a/lnwallet/transactions_test.go +++ b/lnwallet/transactions_test.go @@ -974,8 +974,10 @@ func createTestChannelsForVectors(tc *testContext, chanType channeldb.ChannelTyp ) remoteChannelState := &channeldb.OpenChannel{ - LocalChanCfg: remoteCfg, - RemoteChanCfg: localCfg, + ChanCfgs: lntypes.Dual[channeldb.ChannelConfig]{ + Local: remoteCfg, + Remote: localCfg, + }, IdentityPub: remoteDummy2.PubKey(), FundingOutpoint: *prevOut, ShortChannelID: shortChanID, @@ -992,8 +994,10 @@ func createTestChannelsForVectors(tc *testContext, chanType channeldb.ChannelTyp FundingTxn: tc.fundingTx.MsgTx(), } localChannelState := &channeldb.OpenChannel{ - LocalChanCfg: localCfg, - RemoteChanCfg: remoteCfg, + ChanCfgs: lntypes.Dual[channeldb.ChannelConfig]{ + Local: localCfg, + Remote: remoteCfg, + }, IdentityPub: localDummy2.PubKey(), FundingOutpoint: *prevOut, ShortChannelID: shortChanID, diff --git a/lnwallet/wallet.go b/lnwallet/wallet.go index a9018437d5c..78f961fbfdd 100644 --- a/lnwallet/wallet.go +++ b/lnwallet/wallet.go @@ -2318,8 +2318,8 @@ func (l *LightningWallet) handleFundingCounterPartySigs(msg *addCounterPartySigs // As we've completed the funding process, we'll no convert the // contribution structs into their underlying channel config objects to // he stored within the database. - res.partialState.LocalChanCfg = res.ourContribution.toChanConfig() - res.partialState.RemoteChanCfg = res.theirContribution.toChanConfig() + res.partialState.ChanCfgs.Local = res.ourContribution.toChanConfig() + res.partialState.ChanCfgs.Remote = res.theirContribution.toChanConfig() // We'll also record the finalized funding txn, which will allow us to // rebroadcast on startup in case we fail. @@ -2525,8 +2525,10 @@ func (l *LightningWallet) handleSingleFunderSigs(req *addSingleFunderSigsMsg) { // Add the complete funding transaction to the DB, in it's open bucket // which will be used for the lifetime of this channel. - chanState.LocalChanCfg = pendingReservation.ourContribution.toChanConfig() - chanState.RemoteChanCfg = pendingReservation.theirContribution.toChanConfig() + chanState.ChanCfgs.Local = + pendingReservation.ourContribution.toChanConfig() + chanState.ChanCfgs.Remote = + pendingReservation.theirContribution.toChanConfig() chanState.RevocationKeyLocator = pendingReservation.nextRevocationKeyLoc @@ -2620,8 +2622,8 @@ func (l *LightningWallet) ValidateChannel(channelState *channeldb.OpenChannel, return err } - localKey := channelState.LocalChanCfg.MultiSigKey.PubKey - remoteKey := channelState.RemoteChanCfg.MultiSigKey.PubKey + localKey := channelState.ChanCfgs.Local.MultiSigKey.PubKey + remoteKey := channelState.ChanCfgs.Remote.MultiSigKey.PubKey // We'll also need the multi-sig witness script itself so the // chanvalidate package can check it for correctness against the diff --git a/peer/test_utils.go b/peer/test_utils.go index 9034bb5a962..8c579df3ffb 100644 --- a/peer/test_utils.go +++ b/peer/test_utils.go @@ -244,8 +244,10 @@ func createTestPeerWithChannel(t *testing.T, updateChan func(a, ) aliceChannelState := &channeldb.OpenChannel{ - LocalChanCfg: aliceCfg, - RemoteChanCfg: bobCfg, + ChanCfgs: lntypes.Dual[channeldb.ChannelConfig]{ + Local: aliceCfg, + Remote: bobCfg, + }, IdentityPub: aliceKeyPub, FundingOutpoint: *prevOut, ShortChannelID: shortChanID, @@ -262,8 +264,10 @@ func createTestPeerWithChannel(t *testing.T, updateChan func(a, FundingTxn: channels.TestFundingTx, } bobChannelState := &channeldb.OpenChannel{ - LocalChanCfg: bobCfg, - RemoteChanCfg: aliceCfg, + ChanCfgs: lntypes.Dual[channeldb.ChannelConfig]{ + Local: bobCfg, + Remote: aliceCfg, + }, IdentityPub: bobKeyPub, FundingOutpoint: *prevOut, ChanType: channeldb.SingleFunderTweaklessBit, diff --git a/routing/localchans/manager.go b/routing/localchans/manager.go index 2639928e023..f50c56b1839 100644 --- a/routing/localchans/manager.go +++ b/routing/localchans/manager.go @@ -295,9 +295,9 @@ func (r *Manager) createEdge(channel *channeldb.OpenChannel, nodeKey1Bytes := r.SelfPub.SerializeCompressed() nodeKey2Bytes := channel.IdentityPub.SerializeCompressed() - bitcoinKey1Bytes := channel.LocalChanCfg.MultiSigKey.PubKey. + bitcoinKey1Bytes := channel.ChanCfgs.Local.MultiSigKey.PubKey. SerializeCompressed() - bitcoinKey2Bytes := channel.RemoteChanCfg.MultiSigKey.PubKey. + bitcoinKey2Bytes := channel.ChanCfgs.Remote.MultiSigKey.PubKey. SerializeCompressed() channelFlags := lnwire.ChanUpdateChanFlags(0) @@ -449,9 +449,9 @@ func (r *Manager) getHtlcAmtLimits(ch *channeldb.OpenChannel) ( // capacity AND less than or equal to the max in-flight HTLC value. // Since the latter is always less than or equal to the former, just // return the max in-flight value. - maxAmt := ch.LocalChanCfg.ChannelStateBounds.MaxPendingAmount + maxAmt := ch.ChanCfgs.Local.ChannelStateBounds.MaxPendingAmount - return ch.LocalChanCfg.MinHTLC, maxAmt, nil + return ch.ChanCfgs.Local.MinHTLC, maxAmt, nil } // makeFailureItem creates a lnrpc.FailedUpdate object. diff --git a/routing/localchans/manager_test.go b/routing/localchans/manager_test.go index f4512fab2ce..0a956534b04 100644 --- a/routing/localchans/manager_test.go +++ b/routing/localchans/manager_test.go @@ -16,6 +16,7 @@ import ( "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/kvdb" "github.com/lightningnetwork/lnd/lnrpc" + "github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/routing" "github.com/stretchr/testify/require" @@ -150,16 +151,18 @@ func TestManager(t *testing.T) { return &channeldb.OpenChannel{ FundingOutpoint: chanPointValid, IdentityPub: remotepub, - LocalChanCfg: channeldb.ChannelConfig{ - ChannelStateBounds: bounds, - MultiSigKey: keychain.KeyDescriptor{ - PubKey: localMultisigKey, + ChanCfgs: lntypes.Dual[channeldb.ChannelConfig]{ + Local: channeldb.ChannelConfig{ + ChannelStateBounds: bounds, + MultiSigKey: keychain.KeyDescriptor{ + PubKey: localMultisigKey, + }, }, - }, - RemoteChanCfg: channeldb.ChannelConfig{ - ChannelStateBounds: bounds, - MultiSigKey: keychain.KeyDescriptor{ - PubKey: remoteMultisigKey, + Remote: channeldb.ChannelConfig{ + ChannelStateBounds: bounds, + MultiSigKey: keychain.KeyDescriptor{ + PubKey: remoteMultisigKey, + }, }, }, }, nil @@ -365,16 +368,19 @@ func TestCreateEdgeLower(t *testing.T) { channel := &channeldb.OpenChannel{ IdentityPub: remotepub, - LocalChanCfg: channeldb.ChannelConfig{ - MultiSigKey: keychain.KeyDescriptor{ - PubKey: localMultisigKey, + ChanCfgs: lntypes.Dual[channeldb.ChannelConfig]{ + Local: channeldb.ChannelConfig{ + MultiSigKey: keychain.KeyDescriptor{ + PubKey: localMultisigKey, + }, }, - }, - RemoteChanCfg: channeldb.ChannelConfig{ - MultiSigKey: keychain.KeyDescriptor{ - PubKey: remoteMultisigKey, + Remote: channeldb.ChannelConfig{ + MultiSigKey: keychain.KeyDescriptor{ + PubKey: remoteMultisigKey, + }, }, }, + ShortChannelID: lnwire.NewShortChanIDFromInt(8), ChainHash: *chaincfg.RegressionNetParams.GenesisHash, Capacity: 9, @@ -453,14 +459,16 @@ func TestCreateEdgeHigher(t *testing.T) { channel := &channeldb.OpenChannel{ IdentityPub: remotepub, - LocalChanCfg: channeldb.ChannelConfig{ - MultiSigKey: keychain.KeyDescriptor{ - PubKey: localMultisigKey, + ChanCfgs: lntypes.Dual[channeldb.ChannelConfig]{ + Local: channeldb.ChannelConfig{ + MultiSigKey: keychain.KeyDescriptor{ + PubKey: localMultisigKey, + }, }, - }, - RemoteChanCfg: channeldb.ChannelConfig{ - MultiSigKey: keychain.KeyDescriptor{ - PubKey: remoteMultisigKey, + Remote: channeldb.ChannelConfig{ + MultiSigKey: keychain.KeyDescriptor{ + PubKey: remoteMultisigKey, + }, }, }, ShortChannelID: lnwire.NewShortChanIDFromInt(8), diff --git a/rpcserver.go b/rpcserver.go index d23066a1fbe..3fea4248ee8 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -3862,8 +3862,10 @@ func (r *rpcServer) fetchPendingOpenChannels() (pendingOpenChannels, error) { Capacity: int64(pendingChan.Capacity), LocalBalance: int64(localCommitment.LocalBalance.ToSatoshis()), RemoteBalance: int64(localCommitment.RemoteBalance.ToSatoshis()), - LocalChanReserveSat: int64(pendingChan.LocalChanCfg.ChanReserve), - RemoteChanReserveSat: int64(pendingChan.RemoteChanCfg.ChanReserve), + //nolint:lll + LocalChanReserveSat: int64(pendingChan.ChanCfgs.Local.ChanReserve), + //nolint:lll + RemoteChanReserveSat: int64(pendingChan.ChanCfgs.Remote.ChanReserve), Initiator: rpcInitiator(pendingChan.IsInitiator), CommitmentType: rpcCommitmentType(pendingChan.ChanType), Private: isPrivate(pendingChan), @@ -4153,8 +4155,10 @@ func (r *rpcServer) fetchWaitingCloseChannels( Capacity: int64(waitingClose.Capacity), LocalBalance: int64(waitingClose.LocalCommitment.LocalBalance.ToSatoshis()), RemoteBalance: int64(waitingClose.LocalCommitment.RemoteBalance.ToSatoshis()), - LocalChanReserveSat: int64(waitingClose.LocalChanCfg.ChanReserve), - RemoteChanReserveSat: int64(waitingClose.RemoteChanCfg.ChanReserve), + //nolint:lll + LocalChanReserveSat: int64(waitingClose.ChanCfgs.Local.ChanReserve), + //nolint:lll + RemoteChanReserveSat: int64(waitingClose.ChanCfgs.Remote.ChanReserve), Initiator: rpcInitiator(waitingClose.IsInitiator), CommitmentType: rpcCommitmentType(waitingClose.ChanType), NumForwardingPackages: int64(len(fwdPkgs)), @@ -4736,10 +4740,10 @@ func createRPCOpenChannel(r *rpcServer, dbChannel *channeldb.OpenChannel, CommitmentType: commitmentType, ThawHeight: dbChannel.ThawHeight, LocalConstraints: createChannelConstraint( - &dbChannel.LocalChanCfg, + &dbChannel.ChanCfgs.Local, ), RemoteConstraints: createChannelConstraint( - &dbChannel.RemoteChanCfg, + &dbChannel.ChanCfgs.Remote, ), AliasScids: make([]uint64, 0, len(channelAliases)), PeerScidAlias: peerScidAlias.ToUint64(), @@ -4748,9 +4752,11 @@ func createRPCOpenChannel(r *rpcServer, dbChannel *channeldb.OpenChannel, Memo: string(dbChannel.Memo), CustomChannelData: customChanBytes, // TODO: remove the following deprecated fields - CsvDelay: uint32(dbChannel.LocalChanCfg.CsvDelay), - LocalChanReserveSat: int64(dbChannel.LocalChanCfg.ChanReserve), - RemoteChanReserveSat: int64(dbChannel.RemoteChanCfg.ChanReserve), + CsvDelay: uint32(dbChannel.ChanCfgs.Local.CsvDelay), + //nolint:lll + LocalChanReserveSat: int64(dbChannel.ChanCfgs.Local.ChanReserve), + //nolint:lll + RemoteChanReserveSat: int64(dbChannel.ChanCfgs.Remote.ChanReserve), } // Look up our channel peer's node alias if the caller requests it. From 0061382ee1ef009afbd6809f2bc1d955b0c441da Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Tue, 20 Aug 2024 19:38:05 -0600 Subject: [PATCH 11/15] multi: pack ChannelCommitments into Dual in OpenChannel --- chanbackup/backup.go | 2 +- chanbackup/single_test.go | 4 +- channeldb/channel.go | 50 +++-- channeldb/channel_test.go | 90 ++++----- channeldb/db.go | 15 +- contractcourt/breach_arbitrator_test.go | 22 ++- contractcourt/chain_arbitrator.go | 4 +- contractcourt/chain_watcher.go | 4 +- contractcourt/chain_watcher_test.go | 6 +- funding/manager.go | 7 +- htlcswitch/link.go | 7 +- htlcswitch/test_utils.go | 26 +-- lnrpc/invoicesrpc/addinvoice.go | 6 +- lnrpc/invoicesrpc/addinvoice_test.go | 25 ++- lnrpc/walletrpc/walletkit_server.go | 8 +- lnwallet/channel.go | 80 ++++---- lnwallet/channel_test.go | 243 +++++++++++++----------- lnwallet/commitment.go | 2 +- lnwallet/reservation.go | 28 +-- lnwallet/test_utils.go | 22 ++- lnwallet/transactions_test.go | 24 ++- lnwallet/wallet.go | 33 ++-- peer/test_utils.go | 22 ++- pilot.go | 4 +- rpcserver.go | 64 ++++--- 25 files changed, 434 insertions(+), 364 deletions(-) diff --git a/chanbackup/backup.go b/chanbackup/backup.go index 5d9d769e878..357ff1e176c 100644 --- a/chanbackup/backup.go +++ b/chanbackup/backup.go @@ -66,7 +66,7 @@ func buildCloseTxInputs( log.Debugf("Crafting CloseTxInputs for ChannelPoint(%v)", targetChan.FundingOutpoint) - localCommit := targetChan.LocalCommitment + localCommit := targetChan.Commitments.Local if localCommit.CommitTx == nil { log.Infof("CommitTx is nil for ChannelPoint(%v), "+ diff --git a/chanbackup/single_test.go b/chanbackup/single_test.go index dd5bd1a816a..4730220915d 100644 --- a/chanbackup/single_test.go +++ b/chanbackup/single_test.go @@ -242,7 +242,9 @@ func genRandomOpenChannelShell() (*channeldb.OpenChannel, error) { ), ThawHeight: rand.Uint32(), IdentityPub: pub, - LocalCommitment: localCommit, + Commitments: lntypes.Dual[channeldb.ChannelCommitment]{ + Local: localCommit, + }, RevocationProducer: shaChainProducer, TapscriptRoot: tapscriptRootOption, ChanCfgs: lntypes.Dual[channeldb.ChannelConfig]{ diff --git a/channeldb/channel.go b/channeldb/channel.go index 5a59be91562..d775e3abf2d 100644 --- a/channeldb/channel.go +++ b/channeldb/channel.go @@ -941,17 +941,11 @@ type OpenChannel struct { // ChanCfgs is the channel configuration for the local and remote nodes. ChanCfgs lntypes.Dual[ChannelConfig] - // LocalCommitment is the current local commitment state for the local - // party. This is stored distinct from the state of the remote party - // as there are certain asymmetric parameters which affect the - // structure of each commitment. - LocalCommitment ChannelCommitment - - // RemoteCommitment is the current remote commitment state for the - // remote party. This is stored distinct from the state of the local - // party as there are certain asymmetric parameters which affect the - // structure of each commitment. - RemoteCommitment ChannelCommitment + // Commitments is the pair of ChannelCommitments for both the + // local and remote parties. They are stored distinctly as there are + // certain asymmetric parameters which affect the structure of each + // commitment. + Commitments lntypes.Dual[ChannelCommitment] // RemoteCurrentRevocation is the current revocation for their // commitment transaction. However, since this the derived public key, @@ -1048,13 +1042,13 @@ func (c *OpenChannel) String() string { indexStr := "height=%v, local_htlc_index=%v, local_log_index=%v, " + "remote_htlc_index=%v, remote_log_index=%v" - commit := c.LocalCommitment + commit := c.Commitments.Local local := fmt.Sprintf(indexStr, commit.CommitHeight, commit.LocalHtlcIndex, commit.LocalLogIndex, commit.RemoteHtlcIndex, commit.RemoteLogIndex, ) - commit = c.RemoteCommitment + commit = c.Commitments.Remote remote := fmt.Sprintf(indexStr, commit.CommitHeight, commit.LocalHtlcIndex, commit.LocalLogIndex, commit.RemoteHtlcIndex, commit.RemoteLogIndex, @@ -1760,13 +1754,13 @@ func (c *OpenChannel) ChanSyncMsg() (*lnwire.ChannelReestablish, error) { // one. If the receiver thinks that our commitment height is actually // *equal* to this value, then they'll re-send the last commitment that // they sent but we never fully processed. - localHeight := c.LocalCommitment.CommitHeight + localHeight := c.Commitments.Local.CommitHeight nextLocalCommitHeight := localHeight + 1 // The second value we'll send is the height of the remote commitment // from our PoV. If the receiver thinks that their height is actually // *one plus* this value, then they'll re-send their last revocation. - remoteChainTipHeight := c.RemoteCommitment.CommitHeight + remoteChainTipHeight := c.Commitments.Remote.CommitHeight // If this channel has undergone a commitment update, then in order to // prove to the remote party our knowledge of their prior commitment @@ -2410,7 +2404,7 @@ func (c *OpenChannel) UpdateCommitment(newCommitment *ChannelCommitment, return nil, err } - c.LocalCommitment = *newCommitment + c.Commitments.Local = *newCommitment return finalHtlcs, nil } @@ -2471,7 +2465,7 @@ func (c *OpenChannel) ActiveHtlcs() []HTLC { // transactions. So we'll iterate through their set of HTLC's to note // which ones are present on their commitment. remoteHtlcs := make(map[[32]byte]struct{}) - for _, htlc := range c.RemoteCommitment.Htlcs { + for _, htlc := range c.Commitments.Remote.Htlcs { log.Tracef("RemoteCommitment has htlc: id=%v, update=%v "+ "incoming=%v", htlc.HtlcIndex, htlc.LogIndex, htlc.Incoming) @@ -2483,7 +2477,7 @@ func (c *OpenChannel) ActiveHtlcs() []HTLC { // Now that we know which HTLC's they have, we'll only mark the HTLC's // as active if *we* know them as well. activeHtlcs := make([]HTLC, 0, len(remoteHtlcs)) - for _, htlc := range c.LocalCommitment.Htlcs { + for _, htlc := range c.Commitments.Local.Htlcs { log.Tracef("LocalCommitment has htlc: id=%v, update=%v "+ "incoming=%v", htlc.HtlcIndex, htlc.LogIndex, htlc.Incoming) @@ -3327,7 +3321,7 @@ func (c *OpenChannel) AdvanceCommitChainTail(fwdPkg *FwdPkg, // With the commitment pointer swapped, we can now add the // revoked (prior) state to the revocation log. err = putRevocationLog( - logBucket, &c.RemoteCommitment, ourOutputIndex, + logBucket, &c.Commitments.Remote, ourOutputIndex, theirOutputIndex, c.Db.parent.noRevLogAmtData, ) if err != nil { @@ -3409,7 +3403,7 @@ func (c *OpenChannel) AdvanceCommitChainTail(fwdPkg *FwdPkg, // With the db transaction complete, we'll swap over the in-memory // pointer of the new remote commitment, which was previously the tip // of the commit chain. - c.RemoteCommitment = *newRemoteCommit + c.Commitments.Remote = *newRemoteCommit return nil } @@ -3464,7 +3458,7 @@ func (c *OpenChannel) NextLocalHtlcIndex() (uint64, error) { } // Otherwise, fallback to using the local htlc index of their commitment. - return c.RemoteCommitment.LocalHtlcIndex, nil + return c.Commitments.Remote.LocalHtlcIndex, nil } // LoadFwdPkgs scans the forwarding log for any packages that haven't been @@ -3559,7 +3553,7 @@ func (c *OpenChannel) revocationLogTailCommitHeight() (uint64, error) { // If we haven't created any state updates yet, then we'll exit early as // there's nothing to be found on disk in the revocation bucket. - if c.RemoteCommitment.CommitHeight == 0 { + if c.Commitments.Remote.CommitHeight == 0 { return height, nil } @@ -3981,7 +3975,7 @@ func (c *OpenChannel) Snapshot() *ChannelSnapshot { c.RLock() defer c.RUnlock() - localCommit := c.LocalCommitment + localCommit := c.Commitments.Local snapshot := &ChannelSnapshot{ RemoteIdentity: *c.IdentityPub, ChannelPoint: c.FundingOutpoint, @@ -4033,7 +4027,7 @@ func (c *OpenChannel) LatestCommitments() (*ChannelCommitment, *ChannelCommitmen return nil, nil, err } - return &c.LocalCommitment, &c.RemoteCommitment, nil + return &c.Commitments.Local, &c.Commitments.Remote, nil } // RemoteRevocationStore returns the most up to date commitment version of the @@ -4412,14 +4406,14 @@ func putChanCommitments(chanBucket kvdb.RwBucket, channel *OpenChannel) error { } err := putChanCommitment( - chanBucket, &channel.LocalCommitment, true, + chanBucket, &channel.Commitments.Local, true, ) if err != nil { return err } return putChanCommitment( - chanBucket, &channel.RemoteCommitment, false, + chanBucket, &channel.Commitments.Remote, false, ) } @@ -4590,11 +4584,11 @@ func fetchChanCommitments(chanBucket kvdb.RBucket, channel *OpenChannel) error { return nil } - channel.LocalCommitment, err = fetchChanCommitment(chanBucket, true) + channel.Commitments.Local, err = fetchChanCommitment(chanBucket, true) if err != nil { return err } - channel.RemoteCommitment, err = fetchChanCommitment(chanBucket, false) + channel.Commitments.Remote, err = fetchChanCommitment(chanBucket, false) if err != nil { return err } diff --git a/channeldb/channel_test.go b/channeldb/channel_test.go index 91ad13e97ec..af17297902e 100644 --- a/channeldb/channel_test.go +++ b/channeldb/channel_test.go @@ -118,7 +118,7 @@ func openChannelOption() testChannelOption { // commitment. func localHtlcsOption(htlcs []HTLC) testChannelOption { return func(params *testChannelParams) { - params.channel.LocalCommitment.Htlcs = htlcs + params.channel.Commitments.Local.Htlcs = htlcs } } @@ -126,7 +126,7 @@ func localHtlcsOption(htlcs []HTLC) testChannelOption { // commitment. func remoteHtlcsOption(htlcs []HTLC) testChannelOption { return func(params *testChannelParams) { - params.channel.RemoteCommitment.Htlcs = htlcs + params.channel.Commitments.Remote.Htlcs = htlcs } } @@ -331,39 +331,41 @@ func createTestChannelState(t *testing.T, cdb *ChannelStateDB) *OpenChannel { copy(tapscriptRoot[:], bytes.Repeat([]byte{1}, 32)) return &OpenChannel{ - ChanType: SingleFunderBit | FrozenBit, - ChainHash: key, - FundingOutpoint: op, - ShortChannelID: chanID, - IsInitiator: true, - IsPending: true, - IdentityPub: pubKey, - Capacity: btcutil.Amount(10000), + ChanType: SingleFunderBit | FrozenBit, + ChainHash: key, + FundingOutpoint: op, + ShortChannelID: chanID, + IsInitiator: true, + IsPending: true, + IdentityPub: pubKey, + Capacity: btcutil.Amount(10000), ChanCfgs: lntypes.Dual[ChannelConfig]{ Local: localCfg, Remote: remoteCfg, }, TotalMSatSent: 8, TotalMSatReceived: 2, - LocalCommitment: ChannelCommitment{ - CommitHeight: 0, - LocalBalance: lnwire.MilliSatoshi(9000), - RemoteBalance: lnwire.MilliSatoshi(3000), - CommitFee: btcutil.Amount(rand.Int63()), - FeePerKw: btcutil.Amount(5000), - CommitTx: channels.TestFundingTx, - CommitSig: bytes.Repeat([]byte{1}, 71), - CustomBlob: fn.Some([]byte{1, 2, 3}), - }, - RemoteCommitment: ChannelCommitment{ - CommitHeight: 0, - LocalBalance: lnwire.MilliSatoshi(3000), - RemoteBalance: lnwire.MilliSatoshi(9000), - CommitFee: btcutil.Amount(rand.Int63()), - FeePerKw: btcutil.Amount(5000), - CommitTx: channels.TestFundingTx, - CommitSig: bytes.Repeat([]byte{1}, 71), - CustomBlob: fn.Some([]byte{4, 5, 6}), + Commitments: lntypes.Dual[ChannelCommitment]{ + Local: ChannelCommitment{ + CommitHeight: 0, + LocalBalance: lnwire.MilliSatoshi(9000), + RemoteBalance: lnwire.MilliSatoshi(3000), + CommitFee: btcutil.Amount(rand.Int63()), + FeePerKw: btcutil.Amount(5000), + CommitTx: channels.TestFundingTx, + CommitSig: bytes.Repeat([]byte{1}, 71), + CustomBlob: fn.Some([]byte{1, 2, 3}), + }, + Remote: ChannelCommitment{ + CommitHeight: 0, + LocalBalance: lnwire.MilliSatoshi(3000), + RemoteBalance: lnwire.MilliSatoshi(9000), + CommitFee: btcutil.Amount(rand.Int63()), + FeePerKw: btcutil.Amount(5000), + CommitTx: channels.TestFundingTx, + CommitSig: bytes.Repeat([]byte{1}, 71), + CustomBlob: fn.Some([]byte{4, 5, 6}), + }, }, NumConfsRequired: 4, RemoteCurrentRevocation: privKey.PubKey(), @@ -661,7 +663,7 @@ func TestChannelStateTransition(t *testing.T) { // Additionally, modify the signature and commitment transaction. newSequence := uint32(129498) newSig := bytes.Repeat([]byte{3}, 71) - newTx := channel.LocalCommitment.CommitTx.Copy() + newTx := channel.Commitments.Local.CommitTx.Copy() newTx.TxIn[0].Sequence = newSequence commitment := ChannelCommitment{ CommitHeight: 1, @@ -714,11 +716,9 @@ func TestChannelStateTransition(t *testing.T) { // have been updated. updatedChannel, err := cdb.FetchOpenChannels(channel.IdentityPub) require.NoError(t, err, "unable to fetch updated channel") - assertCommitmentEqual( - t, &commitment, &updatedChannel[0].LocalCommitment, + t, &commitment, &updatedChannel[0].Commitments.Local, ) - numDiskUpdates, err := updatedChannel[0].CommitmentHeight() require.NoError(t, err, "unable to read commitment height from disk") @@ -790,7 +790,7 @@ func TestChannelStateTransition(t *testing.T) { // We'll save the old remote commitment as this will be added to the // revocation log shortly. - oldRemoteCommit := channel.RemoteCommitment + oldRemoteCommit := channel.Commitments.Remote // Next, write to the log which tracks the necessary revocation state // needed to rectify any fishy behavior by the remote party. Modify the @@ -842,7 +842,7 @@ func TestChannelStateTransition(t *testing.T) { t.Fatal("update number doesn't match") } - oldRemoteCommit = channel.RemoteCommitment + oldRemoteCommit = channel.Commitments.Remote // Next modify the posted diff commitment slightly, then create a new // commitment diff and advance the tail. @@ -1019,15 +1019,17 @@ func TestFetchClosedChannels(t *testing.T) { // Next, close the channel by including a close channel summary in the // database. summary := &ChannelCloseSummary{ - ChanPoint: state.FundingOutpoint, - ClosingTXID: rev, - RemotePub: state.IdentityPub, - Capacity: state.Capacity, - SettledBalance: state.LocalCommitment.LocalBalance.ToSatoshis(), - TimeLockedBalance: state.RemoteCommitment.LocalBalance.ToSatoshis() + 10000, - CloseType: RemoteForceClose, - IsPending: true, - LocalChanConfig: state.ChanCfgs.Local, + ChanPoint: state.FundingOutpoint, + ClosingTXID: rev, + RemotePub: state.IdentityPub, + Capacity: state.Capacity, + SettledBalance: state.Commitments.Local. + LocalBalance.ToSatoshis(), + TimeLockedBalance: state.Commitments.Remote. + LocalBalance.ToSatoshis() + 10000, + CloseType: RemoteForceClose, + IsPending: true, + LocalChanConfig: state.ChanCfgs.Local, } if err := state.CloseChannel(summary); err != nil { t.Fatalf("unable to close channel: %v", err) diff --git a/channeldb/db.go b/channeldb/db.go index 715eb38510f..2b7b0669ab8 100644 --- a/channeldb/db.go +++ b/channeldb/db.go @@ -1420,13 +1420,14 @@ func (c *ChannelStateDB) AbandonChannel(chanPoint *wire.OutPoint, // channel as possible. We also ensure that we set Pending to false, to // indicate that this channel has been "fully" closed. summary := &ChannelCloseSummary{ - CloseType: Abandoned, - ChanPoint: *chanPoint, - ChainHash: dbChan.ChainHash, - CloseHeight: bestHeight, - RemotePub: dbChan.IdentityPub, - Capacity: dbChan.Capacity, - SettledBalance: dbChan.LocalCommitment.LocalBalance.ToSatoshis(), + CloseType: Abandoned, + ChanPoint: *chanPoint, + ChainHash: dbChan.ChainHash, + CloseHeight: bestHeight, + RemotePub: dbChan.IdentityPub, + Capacity: dbChan.Capacity, + SettledBalance: dbChan.Commitments.Local. + LocalBalance.ToSatoshis(), ShortChanID: dbChan.ShortChanID(), RemoteCurrentRevocation: dbChan.RemoteCurrentRevocation, RemoteNextRevocation: dbChan.RemoteNextRevocation, diff --git a/contractcourt/breach_arbitrator_test.go b/contractcourt/breach_arbitrator_test.go index faf36f5e6f9..a606641622f 100644 --- a/contractcourt/breach_arbitrator_test.go +++ b/contractcourt/breach_arbitrator_test.go @@ -2347,11 +2347,13 @@ func createInitChannels(t *testing.T) ( RemoteCurrentRevocation: bobCommitPoint, RevocationProducer: alicePreimageProducer, RevocationStore: shachain.NewRevocationStore(), - LocalCommitment: aliceCommit, - RemoteCommitment: aliceCommit, - Db: dbAlice.ChannelStateDB(), - Packager: channeldb.NewChannelPackager(shortChanID), - FundingTxn: channels.TestFundingTx, + Commitments: lntypes.Dual[channeldb.ChannelCommitment]{ + Local: aliceCommit, + Remote: aliceCommit, + }, + Db: dbAlice.ChannelStateDB(), + Packager: channeldb.NewChannelPackager(shortChanID), + FundingTxn: channels.TestFundingTx, } bobChannelState := &channeldb.OpenChannel{ ChanCfgs: lntypes.Dual[channeldb.ChannelConfig]{ @@ -2367,10 +2369,12 @@ func createInitChannels(t *testing.T) ( RemoteCurrentRevocation: aliceCommitPoint, RevocationProducer: bobPreimageProducer, RevocationStore: shachain.NewRevocationStore(), - LocalCommitment: bobCommit, - RemoteCommitment: bobCommit, - Db: dbBob.ChannelStateDB(), - Packager: channeldb.NewChannelPackager(shortChanID), + Commitments: lntypes.Dual[channeldb.ChannelCommitment]{ + Local: bobCommit, + Remote: bobCommit, + }, + Db: dbBob.ChannelStateDB(), + Packager: channeldb.NewChannelPackager(shortChanID), } aliceSigner := input.NewMockSigner( diff --git a/contractcourt/chain_arbitrator.go b/contractcourt/chain_arbitrator.go index d7d10ba252c..9f70f60e7e4 100644 --- a/contractcourt/chain_arbitrator.go +++ b/contractcourt/chain_arbitrator.go @@ -473,8 +473,8 @@ func newActiveChannelArbitrator(channel *channeldb.OpenChannel, // Finally, we'll need to construct a series of htlc Sets based on all // currently known valid commitments. htlcSets := make(map[HtlcSetKey]htlcSet) - htlcSets[LocalHtlcSet] = newHtlcSet(channel.LocalCommitment.Htlcs) - htlcSets[RemoteHtlcSet] = newHtlcSet(channel.RemoteCommitment.Htlcs) + htlcSets[LocalHtlcSet] = newHtlcSet(channel.Commitments.Local.Htlcs) + htlcSets[RemoteHtlcSet] = newHtlcSet(channel.Commitments.Remote.Htlcs) pendingRemoteCommitment, err := channel.RemoteCommitChainTip() if err != nil && err != channeldb.ErrNoPendingCommit { diff --git a/contractcourt/chain_watcher.go b/contractcourt/chain_watcher.go index 1997496808b..8a7fcf5774b 100644 --- a/contractcourt/chain_watcher.go +++ b/contractcourt/chain_watcher.go @@ -436,8 +436,8 @@ func (c *chainWatcher) handleUnknownLocalState( func(s lnwallet.AuxLeafStore) fn.Result[lnwallet.CommitDiffAuxResult] { return s.FetchLeavesFromCommit( lnwallet.NewAuxChanState(c.cfg.chanState), - c.cfg.chanState.LocalCommitment, *commitKeyRing, - lntypes.Local, + c.cfg.chanState.Commitments.Local, + *commitKeyRing, lntypes.Local, ) }, ).Unpack() diff --git a/contractcourt/chain_watcher_test.go b/contractcourt/chain_watcher_test.go index 947f17cb0b6..30256b086b4 100644 --- a/contractcourt/chain_watcher_test.go +++ b/contractcourt/chain_watcher_test.go @@ -55,7 +55,7 @@ func TestChainWatcherRemoteUnilateralClose(t *testing.T) { // If we simulate an immediate broadcast of the current commitment by // Bob, then the chain watcher should detect this case. - bobCommit := bobChannel.State().LocalCommitment.CommitTx + bobCommit := bobChannel.State().Commitments.Local.CommitTx bobTxHash := bobCommit.TxHash() bobSpend := &chainntnfs.SpendDetail{ SpenderTxHash: &bobTxHash, @@ -320,7 +320,7 @@ func TestChainWatcherDataLossProtect(t *testing.T) { // Now we'll trigger the channel close event to trigger the // scenario. - bobCommit := bobChannel.State().LocalCommitment.CommitTx + bobCommit := bobChannel.State().Commitments.Local.CommitTx bobTxHash := bobCommit.TxHash() bobSpend := &chainntnfs.SpendDetail{ SpenderTxHash: &bobTxHash, @@ -480,7 +480,7 @@ func TestChainWatcherLocalForceCloseDetect(t *testing.T) { // Next, we'll obtain Alice's commitment transaction and // trigger a force close. This should cause her to detect a // local force close, and dispatch a local close event. - aliceCommit := aliceChannel.State().LocalCommitment.CommitTx + aliceCommit := aliceChannel.State().Commitments.Local.CommitTx // Since this is Alice's commitment, her output is always first // since she's the one creating the HTLCs (lower balance). In diff --git a/funding/manager.go b/funding/manager.go index aa52f51e8dd..108157365f9 100644 --- a/funding/manager.go +++ b/funding/manager.go @@ -2542,7 +2542,8 @@ func (f *Manager) fundeeProcessFundingCreated(peer lnpeer.Peer, // we use this convenience method to delete the pending OpenChannel // from the database. deleteFromDatabase := func() { - localBalance := completeChan.LocalCommitment.LocalBalance.ToSatoshis() + localBalance := completeChan.Commitments.Local. + LocalBalance.ToSatoshis() closeInfo := &channeldb.ChannelCloseSummary{ ChanPoint: completeChan.FundingOutpoint, ChainHash: completeChan.ChainHash, @@ -2907,7 +2908,7 @@ func (f *Manager) fundingTimeout(c *channeldb.OpenChannel, // We'll get a timeout if the number of blocks mined since the channel // was initiated reaches MaxWaitNumBlocksFundingConf and we are not the // channel initiator. - localBalance := c.LocalCommitment.LocalBalance.ToSatoshis() + localBalance := c.Commitments.Local.LocalBalance.ToSatoshis() closeInfo := &channeldb.ChannelCloseSummary{ ChainHash: c.ChainHash, ChanPoint: c.FundingOutpoint, @@ -3865,7 +3866,7 @@ func genFirstStateMusigNonce(channel *channeldb.OpenChannel, // nonce for the next state the remote party will sign for us. verNonce, err := channeldb.NewMusigVerificationNonce( channel.ChanCfgs.Local.MultiSigKey.PubKey, - channel.LocalCommitment.CommitHeight+1, + channel.Commitments.Local.CommitHeight+1, musig2ShaChain, ) if err != nil { diff --git a/htlcswitch/link.go b/htlcswitch/link.go index 6a4a0306758..0fdac1a6056 100644 --- a/htlcswitch/link.go +++ b/htlcswitch/link.go @@ -2496,7 +2496,8 @@ func (l *channelLink) handleUpstreamMsg(msg lnwire.Message) { chanID := l.ChanID() err = l.cfg.TowerClient.BackupState( - &chanID, state.RemoteCommitment.CommitHeight-1, + &chanID, + state.Commitments.Remote.CommitHeight-1, ) if err != nil { l.failf(LinkFailureError{ @@ -2960,10 +2961,10 @@ func (l *channelLink) getDustClosure() dustClosure { // NOTE: Part of the dustHandler interface. func (l *channelLink) getCommitFee(remote bool) btcutil.Amount { if remote { - return l.channel.State().RemoteCommitment.CommitFee + return l.channel.State().Commitments.Remote.CommitFee } - return l.channel.State().LocalCommitment.CommitFee + return l.channel.State().Commitments.Local.CommitFee } // exceedsFeeExposureLimit returns whether or not the new proposed fee-rate diff --git a/htlcswitch/test_utils.go b/htlcswitch/test_utils.go index be8b935e93c..7e54269cd49 100644 --- a/htlcswitch/test_utils.go +++ b/htlcswitch/test_utils.go @@ -317,12 +317,14 @@ func createTestChannel(t *testing.T, alicePrivKey, bobPrivKey []byte, RemoteCurrentRevocation: bobCommitPoint, RevocationProducer: alicePreimageProducer, RevocationStore: shachain.NewRevocationStore(), - LocalCommitment: aliceCommit, - RemoteCommitment: aliceCommit, - ShortChannelID: chanID, - Db: dbAlice.ChannelStateDB(), - Packager: channeldb.NewChannelPackager(chanID), - FundingTxn: channels.TestFundingTx, + Commitments: lntypes.Dual[channeldb.ChannelCommitment]{ + Local: aliceCommit, + Remote: aliceCommit, + }, + ShortChannelID: chanID, + Db: dbAlice.ChannelStateDB(), + Packager: channeldb.NewChannelPackager(chanID), + FundingTxn: channels.TestFundingTx, } bobChannelState := &channeldb.OpenChannel{ @@ -338,11 +340,13 @@ func createTestChannel(t *testing.T, alicePrivKey, bobPrivKey []byte, RemoteCurrentRevocation: aliceCommitPoint, RevocationProducer: bobPreimageProducer, RevocationStore: shachain.NewRevocationStore(), - LocalCommitment: bobCommit, - RemoteCommitment: bobCommit, - ShortChannelID: chanID, - Db: dbBob.ChannelStateDB(), - Packager: channeldb.NewChannelPackager(chanID), + Commitments: lntypes.Dual[channeldb.ChannelCommitment]{ + Local: bobCommit, + Remote: bobCommit, + }, + ShortChannelID: chanID, + Db: dbBob.ChannelStateDB(), + Packager: channeldb.NewChannelPackager(chanID), } if err := aliceChannelState.SyncPending(bobAddr, broadcastHeight); err != nil { diff --git a/lnrpc/invoicesrpc/addinvoice.go b/lnrpc/invoicesrpc/addinvoice.go index df274f2da79..c83d3687674 100644 --- a/lnrpc/invoicesrpc/addinvoice.go +++ b/lnrpc/invoicesrpc/addinvoice.go @@ -729,7 +729,7 @@ func newHopHintInfo(c *channeldb.OpenChannel, isActive bool) *HopHintInfo { IsActive: isActive, FundingOutpoint: c.FundingOutpoint, RemotePubkey: c.IdentityPub, - RemoteBalance: c.LocalCommitment.RemoteBalance, + RemoteBalance: c.Commitments.Local.RemoteBalance, ShortChannelID: c.ShortChannelID.ToUint64(), ConfirmedScidZC: c.ZeroConfRealScid().ToUint64(), ScidAliasFeature: c.ChanType.HasScidAliasFeature(), @@ -844,8 +844,8 @@ func getPotentialHints(cfg *SelectHopHintsCfg) ([]*channeldb.OpenChannel, // Sort the channels in descending remote balance. compareRemoteBalance := func(i, j int) bool { - iBalance := privateChannels[i].LocalCommitment.RemoteBalance - jBalance := privateChannels[j].LocalCommitment.RemoteBalance + iBalance := privateChannels[i].Commitments.Local.RemoteBalance + jBalance := privateChannels[j].Commitments.Local.RemoteBalance return iBalance > jBalance } sort.Slice(privateChannels, compareRemoteBalance) diff --git a/lnrpc/invoicesrpc/addinvoice_test.go b/lnrpc/invoicesrpc/addinvoice_test.go index 76a529f8c67..723e31628f5 100644 --- a/lnrpc/invoicesrpc/addinvoice_test.go +++ b/lnrpc/invoicesrpc/addinvoice_test.go @@ -9,6 +9,7 @@ import ( "github.com/btcsuite/btcd/wire" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb/models" + "github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/zpay32" "github.com/stretchr/testify/mock" @@ -588,8 +589,10 @@ var populateHopHintsTestCases = []struct { remoteBalance := lnwire.MilliSatoshi(10_000_000) allChannels := []*channeldb.OpenChannel{ { - LocalCommitment: channeldb.ChannelCommitment{ - RemoteBalance: remoteBalance, + Commitments: lntypes.Dual[channeldb.ChannelCommitment]{ //nolint:lll + Local: channeldb.ChannelCommitment{ + RemoteBalance: remoteBalance, + }, }, FundingOutpoint: fundingOutpoint, ShortChannelID: lnwire.NewShortChanIDFromInt(9), @@ -642,8 +645,10 @@ var populateHopHintsTestCases = []struct { // enough bandwidth we should never use this one. {}, { - LocalCommitment: channeldb.ChannelCommitment{ - RemoteBalance: remoteBalance, + Commitments: lntypes.Dual[channeldb.ChannelCommitment]{ //nolint:lll + Local: channeldb.ChannelCommitment{ + RemoteBalance: remoteBalance, + }, }, FundingOutpoint: fundingOutpoint, ShortChannelID: lnwire.NewShortChanIDFromInt(9), @@ -840,16 +845,20 @@ func setupMockTwoChannels(h *hopHintsConfigMock) (lnwire.ChannelID, // After sorting we will first process chanID1 and then // chanID2. { - LocalCommitment: channeldb.ChannelCommitment{ - RemoteBalance: remoteBalance2, + Commitments: lntypes.Dual[channeldb.ChannelCommitment]{ + Local: channeldb.ChannelCommitment{ + RemoteBalance: remoteBalance2, + }, }, FundingOutpoint: fundingOutpoint2, ShortChannelID: lnwire.NewShortChanIDFromInt(2), IdentityPub: getTestPubKey(), }, { - LocalCommitment: channeldb.ChannelCommitment{ - RemoteBalance: remoteBalance1, + Commitments: lntypes.Dual[channeldb.ChannelCommitment]{ + Local: channeldb.ChannelCommitment{ + RemoteBalance: remoteBalance1, + }, }, FundingOutpoint: fundingOutpoint1, ShortChannelID: lnwire.NewShortChanIDFromInt(9), diff --git a/lnrpc/walletrpc/walletkit_server.go b/lnrpc/walletrpc/walletkit_server.go index 3b16f4da719..11b29934a5e 100644 --- a/lnrpc/walletrpc/walletkit_server.go +++ b/lnrpc/walletrpc/walletkit_server.go @@ -1192,13 +1192,13 @@ func (w *WalletKit) BumpForceCloseFee(_ context.Context, // bumping the fee. commitSet := fn.NewSet[chainhash.Hash]() - if channel.LocalCommitment.CommitTx != nil { - localTxID := channel.LocalCommitment.CommitTx.TxHash() + if channel.Commitments.Local.CommitTx != nil { + localTxID := channel.Commitments.Local.CommitTx.TxHash() commitSet.Add(localTxID) } - if channel.RemoteCommitment.CommitTx != nil { - remoteTxID := channel.RemoteCommitment.CommitTx.TxHash() + if channel.Commitments.Remote.CommitTx != nil { + remoteTxID := channel.Commitments.Remote.CommitTx.TxHash() commitSet.Add(remoteTxID) } diff --git a/lnwallet/channel.go b/lnwallet/channel.go index bdc7c2afe2a..c45acb47c08 100644 --- a/lnwallet/channel.go +++ b/lnwallet/channel.go @@ -910,8 +910,8 @@ func NewLightningChannel(signer input.Signer, optFunc(opts) } - localCommit := state.LocalCommitment - remoteCommit := state.RemoteCommitment + localCommit := state.Commitments.Local + remoteCommit := state.Commitments.Remote // First, initialize the update logs with their current counter values // from the local and remote commitments. @@ -2214,7 +2214,7 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64, KeyRing: keyRing, CsvDelay: ourDelay, BreachCsvDelay: fn.Some(theirDelay), - CommitFee: chanState.RemoteCommitment.CommitFee, + CommitFee: chanState.Commitments.Remote.CommitFee, } if revokedLog != nil { resolveReq.CommitBlob = revokedLog.CustomBlob.ValOpt() @@ -2294,7 +2294,7 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64, KeyRing: keyRing, CsvDelay: theirDelay, BreachCsvDelay: fn.Some(theirDelay), - CommitFee: chanState.RemoteCommitment.CommitFee, + CommitFee: chanState.Commitments.Remote.CommitFee, } if revokedLog != nil { resolveReq.CommitBlob = revokedLog.CustomBlob.ValOpt() @@ -5805,7 +5805,7 @@ func (lc *LightningChannel) ReceiveRevocation(revMsg *lnwire.RevokeAndAck) ( remoteChainTail, ) - remoteHTLCs := lc.channelState.RemoteCommitment.Htlcs + remoteHTLCs := lc.channelState.Commitments.Remote.Htlcs return fwdPkg, remoteHTLCs, nil } @@ -5926,11 +5926,11 @@ func (lc *LightningChannel) GetDustSum(whoseCommit lntypes.ChannelParty, var dustSum lnwire.MilliSatoshi dustLimit := lc.channelState.ChanCfgs.Local.DustLimit - commit := lc.channelState.LocalCommitment + commit := lc.channelState.Commitments.Local if whoseCommit.IsRemote() { // Calculate dust sum on the remote's commitment. dustLimit = lc.channelState.ChanCfgs.Remote.DustLimit - commit = lc.channelState.RemoteCommitment + commit = lc.channelState.Commitments.Remote } chanType := lc.channelState.ChanType @@ -6618,7 +6618,7 @@ func GetSignedCommitTx(inputs SignedCommitTxInputs, func (lc *LightningChannel) getSignedCommitTx() (*wire.MsgTx, error) { // Fetch the current commitment transaction, along with their signature // for the transaction. - localCommit := lc.channelState.LocalCommitment + localCommit := lc.channelState.Commitments.Local inputs := SignedCommitTxInputs{ CommitTx: localCommit.CommitTx, @@ -6852,7 +6852,7 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, //nolint:funlen ChanType: chanState.ChanType, ShortChanID: chanState.ShortChanID(), Initiator: chanState.IsInitiator, - CommitBlob: chanState.RemoteCommitment.CustomBlob, + CommitBlob: chanState.Commitments.Remote.CustomBlob, FundingBlob: chanState.CustomBlob, Type: input.TaprootRemoteCommitSpend, CloseType: RemoteForceClose, @@ -6861,7 +6861,7 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, //nolint:funlen SignDesc: commitResolution.SelfOutputSignDesc, KeyRing: keyRing, CsvDelay: maturityDelay, - CommitFee: chanState.RemoteCommitment.CommitFee, + CommitFee: chanState.Commitments.Remote.CommitFee, } resolveBlob := fn.MapOptionZ( auxResolver, @@ -7128,7 +7128,7 @@ func newOutgoingHtlcResolution(signer input.Signer, ChanType: chanType, ShortChanID: chanState.ShortChanID(), Initiator: chanState.IsInitiator, - CommitBlob: chanState.RemoteCommitment.CustomBlob, + CommitBlob: chanState.Commitments.Remote.CustomBlob, FundingBlob: chanState.CustomBlob, Type: input.TaprootHtlcOfferedRemoteTimeout, CloseType: RemoteForceClose, @@ -7138,7 +7138,7 @@ func newOutgoingHtlcResolution(signer input.Signer, KeyRing: keyRing, CsvDelay: htlcCsvDelay, CltvDelay: fn.Some(htlc.RefundTimeout), - CommitFee: chanState.RemoteCommitment.CommitFee, + CommitFee: chanState.Commitments.Remote.CommitFee, HtlcID: fn.Some(htlc.HtlcIndex), PayHash: fn.Some(htlc.RHash), } @@ -7339,7 +7339,7 @@ func newOutgoingHtlcResolution(signer input.Signer, ChanType: chanType, ShortChanID: chanState.ShortChanID(), Initiator: chanState.IsInitiator, - CommitBlob: chanState.LocalCommitment.CustomBlob, //nolint:lll + CommitBlob: chanState.Commitments.Local.CustomBlob, //nolint:lll FundingBlob: chanState.CustomBlob, Type: input.TaprootHtlcLocalOfferedTimeout, //nolint:lll CloseType: LocalForceClose, @@ -7351,7 +7351,7 @@ func newOutgoingHtlcResolution(signer input.Signer, HtlcAmt: btcutil.Amount(txOut.Value), CommitCsvDelay: csvDelay, CltvDelay: fn.Some(htlc.RefundTimeout), - CommitFee: chanState.LocalCommitment.CommitFee, //nolint:lll + CommitFee: chanState.Commitments.Local.CommitFee, //nolint:lll HtlcID: fn.Some(htlc.HtlcIndex), PayHash: fn.Some(htlc.RHash), AuxSigDesc: fn.Some(AuxSigDesc{ @@ -7474,7 +7474,7 @@ func newIncomingHtlcResolution(signer input.Signer, ChanType: chanType, ShortChanID: chanState.ShortChanID(), Initiator: chanState.IsInitiator, - CommitBlob: chanState.RemoteCommitment.CustomBlob, + CommitBlob: chanState.Commitments.Remote.CustomBlob, Type: input.TaprootHtlcAcceptedRemoteSuccess, FundingBlob: chanState.CustomBlob, CloseType: RemoteForceClose, @@ -7485,7 +7485,7 @@ func newIncomingHtlcResolution(signer input.Signer, HtlcID: fn.Some(htlc.HtlcIndex), CsvDelay: htlcCsvDelay, CltvDelay: fn.Some(htlc.RefundTimeout), - CommitFee: chanState.RemoteCommitment.CommitFee, + CommitFee: chanState.Commitments.Remote.CommitFee, PayHash: fn.Some(htlc.RHash), CommitCsvDelay: csvDelay, HtlcAmt: htlc.Amt.ToSatoshis(), @@ -7679,7 +7679,7 @@ func newIncomingHtlcResolution(signer input.Signer, ChanType: chanType, ShortChanID: chanState.ShortChanID(), Initiator: chanState.IsInitiator, - CommitBlob: chanState.LocalCommitment.CustomBlob, //nolint:lll + CommitBlob: chanState.Commitments.Local.CustomBlob, //nolint:lll Type: input.TaprootHtlcAcceptedLocalSuccess, //nolint:lll FundingBlob: chanState.CustomBlob, CloseType: LocalForceClose, @@ -7689,7 +7689,7 @@ func newIncomingHtlcResolution(signer input.Signer, KeyRing: keyRing, HtlcID: fn.Some(htlc.HtlcIndex), CsvDelay: htlcCsvDelay, - CommitFee: chanState.LocalCommitment.CommitFee, //nolint:lll + CommitFee: chanState.Commitments.Local.CommitFee, //nolint:lll PayHash: fn.Some(htlc.RHash), AuxSigDesc: fn.Some(AuxSigDesc{ SignDetails: *txSignDetails, @@ -7952,7 +7952,7 @@ func (lc *LightningChannel) ForceClose(opts ...ForceCloseOpt) ( }, nil } - localCommitment := lc.channelState.LocalCommitment + localCommitment := lc.channelState.Commitments.Local summary, err := NewLocalForceCloseSummary( lc.channelState, lc.Signer, commitTx, localCommitment.CommitHeight, lc.leafStore, lc.auxResolver, @@ -7999,7 +7999,7 @@ func NewLocalForceCloseSummary(chanState *channeldb.OpenChannel, leafStore, func(s AuxLeafStore) fn.Result[CommitDiffAuxResult] { return s.FetchLeavesFromCommit( NewAuxChanState(chanState), - chanState.LocalCommitment, *keyRing, + chanState.Commitments.Local, *keyRing, lntypes.Local, ) }, @@ -8111,7 +8111,7 @@ func NewLocalForceCloseSummary(chanState *channeldb.OpenChannel, ChanType: chanState.ChanType, ShortChanID: chanState.ShortChanID(), Initiator: chanState.IsInitiator, - CommitBlob: chanState.LocalCommitment.CustomBlob, + CommitBlob: chanState.Commitments.Local.CustomBlob, FundingBlob: chanState.CustomBlob, Type: input.TaprootLocalCommitSpend, CloseType: LocalForceClose, @@ -8120,7 +8120,7 @@ func NewLocalForceCloseSummary(chanState *channeldb.OpenChannel, SignDesc: commitResolution.SelfOutputSignDesc, KeyRing: keyRing, CsvDelay: csvTimeout, - CommitFee: chanState.LocalCommitment.CommitFee, + CommitFee: chanState.Commitments.Local.CommitFee, }) }, ) @@ -8136,7 +8136,7 @@ func NewLocalForceCloseSummary(chanState *channeldb.OpenChannel, // outgoing HTLC's that we'll need to claim as well. If this is after // recovery there is not much we can do with HTLCs, so we'll always // use what we have in our latest state when extracting resolutions. - localCommit := chanState.LocalCommitment + localCommit := chanState.Commitments.Local htlcResolutions, err := extractHtlcResolutions( chainfee.SatPerKWeight(localCommit.FeePerKw), lntypes.Local, signer, localCommit.Htlcs, keyRing, &chanState.ChanCfgs.Local, @@ -8259,9 +8259,9 @@ func (lc *LightningChannel) CreateCloseProposal(proposedFee btcutil.Amount, ourBalance, theirBalance, err := CoopCloseBalance( lc.channelState.ChanType, lc.channelState.IsInitiator, proposedFee, - lc.channelState.LocalCommitment.LocalBalance.ToSatoshis(), - lc.channelState.LocalCommitment.RemoteBalance.ToSatoshis(), - lc.channelState.LocalCommitment.CommitFee, + lc.channelState.Commitments.Local.LocalBalance.ToSatoshis(), + lc.channelState.Commitments.Local.RemoteBalance.ToSatoshis(), + lc.channelState.Commitments.Local.CommitFee, ) if err != nil { return nil, nil, 0, err @@ -8362,9 +8362,9 @@ func (lc *LightningChannel) CompleteCooperativeClose( ourBalance, theirBalance, err := CoopCloseBalance( lc.channelState.ChanType, lc.channelState.IsInitiator, proposedFee, - lc.channelState.LocalCommitment.LocalBalance.ToSatoshis(), - lc.channelState.LocalCommitment.RemoteBalance.ToSatoshis(), - lc.channelState.LocalCommitment.CommitFee, + lc.channelState.Commitments.Local.LocalBalance.ToSatoshis(), + lc.channelState.Commitments.Local.RemoteBalance.ToSatoshis(), + lc.channelState.Commitments.Local.CommitFee, ) if err != nil { return nil, 0, err @@ -8520,7 +8520,7 @@ func (lc *LightningChannel) NewAnchorResolutions() (*AnchorResolutions, &lc.channelState.ChanCfgs.Remote, ) localRes, err := NewAnchorResolution( - lc.channelState, lc.channelState.LocalCommitment.CommitTx, + lc.channelState, lc.channelState.Commitments.Local.CommitTx, localKeyRing, lntypes.Local, ) if err != nil { @@ -8535,7 +8535,7 @@ func (lc *LightningChannel) NewAnchorResolutions() (*AnchorResolutions, &lc.channelState.ChanCfgs.Remote, ) remoteRes, err := NewAnchorResolution( - lc.channelState, lc.channelState.RemoteCommitment.CommitTx, + lc.channelState, lc.channelState.Commitments.Remote.CommitTx, remoteKeyRing, lntypes.Remote, ) if err != nil { @@ -9308,7 +9308,7 @@ func (lc *LightningChannel) LocalBalanceDust() (bool, btcutil.Amount) { defer lc.RUnlock() chanState := lc.channelState - localBalance := chanState.LocalCommitment.LocalBalance.ToSatoshis() + localBalance := chanState.Commitments.Local.LocalBalance.ToSatoshis() // If this is an anchor channel, and we're the initiator, then we'll // regain the stats allocated to the anchor outputs with the co-op @@ -9330,7 +9330,7 @@ func (lc *LightningChannel) RemoteBalanceDust() (bool, btcutil.Amount) { defer lc.RUnlock() chanState := lc.channelState - remoteBalance := chanState.RemoteCommitment.RemoteBalance.ToSatoshis() + remoteBalance := chanState.Commitments.Remote.RemoteBalance.ToSatoshis() // If this is an anchor channel, and they're the initiator, then we'll // regain the stats allocated to the anchor outputs with the co-op @@ -9351,7 +9351,7 @@ func (lc *LightningChannel) CommitBalances() (btcutil.Amount, btcutil.Amount) { defer lc.RUnlock() chanState := lc.channelState - localCommit := lc.channelState.LocalCommitment + localCommit := lc.channelState.Commitments.Local localBalance := localCommit.LocalBalance.ToSatoshis() remoteBalance := localCommit.RemoteBalance.ToSatoshis() @@ -9372,7 +9372,7 @@ func (lc *LightningChannel) CommitFee() btcutil.Amount { lc.RLock() defer lc.RUnlock() - return lc.channelState.LocalCommitment.CommitFee + return lc.channelState.Commitments.Local.CommitFee } // CalcFee returns the commitment fee to use for the given fee rate @@ -9530,7 +9530,9 @@ func (lc *LightningChannel) CommitFeeRate() chainfee.SatPerKWeight { lc.RLock() defer lc.RUnlock() - return chainfee.SatPerKWeight(lc.channelState.LocalCommitment.FeePerKw) + return chainfee.SatPerKWeight( + lc.channelState.Commitments.Local.FeePerKw, + ) } // WorstCaseFeeRate returns the higher feerate from either the local commitment @@ -9539,8 +9541,8 @@ func (lc *LightningChannel) WorstCaseFeeRate() chainfee.SatPerKWeight { lc.RLock() defer lc.RUnlock() - localFeeRate := lc.channelState.LocalCommitment.FeePerKw - remoteFeeRate := lc.channelState.RemoteCommitment.FeePerKw + localFeeRate := lc.channelState.Commitments.Local.FeePerKw + remoteFeeRate := lc.channelState.Commitments.Remote.FeePerKw if localFeeRate > remoteFeeRate { return chainfee.SatPerKWeight(localFeeRate) @@ -9803,7 +9805,7 @@ func (lc *LightningChannel) LocalCommitmentBlob() fn.Option[tlv.Blob] { defer lc.RUnlock() chanState := lc.channelState - localBalance := chanState.LocalCommitment.CustomBlob + localBalance := chanState.Commitments.Local.CustomBlob return fn.MapOption(func(b tlv.Blob) tlv.Blob { newBlob := make([]byte, len(b)) diff --git a/lnwallet/channel_test.go b/lnwallet/channel_test.go index d56c670c842..c5ae9a40a6a 100644 --- a/lnwallet/channel_test.go +++ b/lnwallet/channel_test.go @@ -228,21 +228,21 @@ func testAddSettleWorkflow(t *testing.T, tweakless bool, // an anchor output. numOutputs = 5 } - if len(aliceChanState.LocalCommitment.CommitTx.TxOut) != numOutputs { + if len(aliceChanState.Commitments.Local.CommitTx.TxOut) != numOutputs { t.Fatalf("alice should have three commitment outputs, instead "+ "have %v", - len(aliceChanState.LocalCommitment.CommitTx.TxOut)) + len(aliceChanState.Commitments.Local.CommitTx.TxOut)) } - if len(bobChanState.LocalCommitment.CommitTx.TxOut) != numOutputs { + if len(bobChanState.Commitments.Local.CommitTx.TxOut) != numOutputs { t.Fatalf("bob should have three commitment outputs, instead "+ "have %v", - len(bobChanState.LocalCommitment.CommitTx.TxOut)) + len(bobChanState.Commitments.Local.CommitTx.TxOut)) } assertOutputExistsByValue(t, - aliceChannel.channelState.LocalCommitment.CommitTx, + aliceChannel.channelState.Commitments.Local.CommitTx, htlcAmt.ToSatoshis()) assertOutputExistsByValue(t, - bobChannel.channelState.LocalCommitment.CommitTx, + bobChannel.channelState.Commitments.Local.CommitTx, htlcAmt.ToSatoshis()) // Now we'll repeat a similar exchange, this time with Bob settling the @@ -804,10 +804,10 @@ func testCoopClose(t *testing.T, testCase *coopCloseTestCase) { bobDeliveryScript := testHdSeed[:] aliceFeeRate := chainfee.SatPerKWeight( - aliceChannel.channelState.LocalCommitment.FeePerKw, + aliceChannel.channelState.Commitments.Local.FeePerKw, ) bobFeeRate := chainfee.SatPerKWeight( - bobChannel.channelState.LocalCommitment.FeePerKw, + bobChannel.channelState.Commitments.Local.FeePerKw, ) // We'll start with both Alice and Bob creating a new close proposal @@ -847,14 +847,14 @@ func testCoopClose(t *testing.T, testCase *coopCloseTestCase) { // Finally, make sure the final balances are correct from both's // perspective. - aliceBalance := aliceChannel.channelState.LocalCommitment. + aliceBalance := aliceChannel.channelState.Commitments.Local. LocalBalance.ToSatoshis() // The commit balance have had the initiator's (Alice) commitfee and // any anchors subtracted, so add that back to the final expected // balance. Alice also pays the coop close fee, so that must be // subtracted. - commitFee := aliceChannel.channelState.LocalCommitment.CommitFee + commitFee := aliceChannel.channelState.Commitments.Local.CommitFee expBalanceAlice := aliceBalance + commitFee + testCase.anchorAmt - bobFee if aliceTxBalance != expBalanceAlice { @@ -864,7 +864,7 @@ func testCoopClose(t *testing.T, testCase *coopCloseTestCase) { // Bob is not the initiator, so his final balance should simply be // equal to the latest commitment balance. - expBalanceBob := bobChannel.channelState.LocalCommitment. + expBalanceBob := bobChannel.channelState.Commitments.Local. LocalBalance.ToSatoshis() if bobTxBalance != expBalanceBob { t.Fatalf("expected bob's balance to be %v got %v", @@ -930,7 +930,7 @@ func testForceClose(t *testing.T, testCase *forceCloseTestCase) { ) require.NoError(t, err, "unable to create test channels") - bobAmount := bobChannel.channelState.LocalCommitment.LocalBalance + bobAmount := bobChannel.channelState.Commitments.Local.LocalBalance // First, we'll add an outgoing HTLC from Alice to Bob, such that it // will still be present within the broadcast commitment transaction. @@ -1032,7 +1032,7 @@ func testForceClose(t *testing.T, testCase *forceCloseTestCase) { totalCommitWeight := testCase.expectedCommitWeight + (input.HTLCWeight * 2) feePerKw := chainfee.SatPerKWeight( - aliceChannel.channelState.LocalCommitment.FeePerKw, + aliceChannel.channelState.Commitments.Local.FeePerKw, ) commitFee := feePerKw.FeeForWeight(totalCommitWeight) @@ -1135,7 +1135,8 @@ func testForceClose(t *testing.T, testCase *forceCloseTestCase) { // Finally, the txid of the commitment transaction and the one returned // as the closing transaction should also match. closeTxHash := closeSummary.CloseTx.TxHash() - commitTxHash := aliceChannel.channelState.LocalCommitment.CommitTx.TxHash() + commitTxHash := + aliceChannel.channelState.Commitments.Local.CommitTx.TxHash() if !bytes.Equal(closeTxHash[:], commitTxHash[:]) { t.Fatalf("alice: incorrect close transaction txid") } @@ -1252,7 +1253,8 @@ func testForceClose(t *testing.T, testCase *forceCloseTestCase) { } closeTxHash = closeSummary.CloseTx.TxHash() - commitTxHash = bobChannel.channelState.LocalCommitment.CommitTx.TxHash() + commitTxHash = + bobChannel.channelState.Commitments.Local.CommitTx.TxHash() if !bytes.Equal(closeTxHash[:], commitTxHash[:]) { t.Fatalf("bob: incorrect close transaction txid") } @@ -1300,8 +1302,8 @@ func TestForceCloseDustOutput(t *testing.T) { htlcAmount := lnwire.NewMSatFromSatoshis(500) - aliceAmount := aliceChannel.channelState.LocalCommitment.LocalBalance - bobAmount := bobChannel.channelState.LocalCommitment.LocalBalance + aliceAmount := aliceChannel.channelState.Commitments.Local.LocalBalance + bobAmount := bobChannel.channelState.Commitments.Local.LocalBalance // Have Bobs' to-self output be below her dust limit and check // ForceCloseSummary again on both peers. @@ -1325,8 +1327,7 @@ func TestForceCloseDustOutput(t *testing.T) { t.Fatalf("Can't update the channel state: %v", err) } - aliceAmount = aliceChannel.channelState.LocalCommitment.LocalBalance - bobAmount = bobChannel.channelState.LocalCommitment.RemoteBalance + aliceAmount = aliceChannel.channelState.Commitments.Local.LocalBalance closeSummary, err := aliceChannel.ForceClose() require.NoError(t, err, "unable to force close channel") @@ -1349,7 +1350,7 @@ func TestForceCloseDustOutput(t *testing.T) { int64(aliceAmount.ToSatoshis()) { t.Fatalf("alice incorrect output value in SelfOutputSignDesc, "+ "expected %v, got %v", - aliceChannel.channelState.LocalCommitment.LocalBalance.ToSatoshis(), + aliceChannel.channelState.Commitments.Local.LocalBalance.ToSatoshis(), //nolint:lll commitResolution.SelfOutputSignDesc.Output.Value) } @@ -1363,7 +1364,8 @@ func TestForceCloseDustOutput(t *testing.T) { } closeTxHash := closeSummary.CloseTx.TxHash() - commitTxHash := aliceChannel.channelState.LocalCommitment.CommitTx.TxHash() + commitTxHash := + aliceChannel.channelState.Commitments.Local.CommitTx.TxHash() if !bytes.Equal(closeTxHash[:], commitTxHash[:]) { t.Fatalf("alice: incorrect close transaction txid") } @@ -1381,7 +1383,8 @@ func TestForceCloseDustOutput(t *testing.T) { } closeTxHash = closeSummary.CloseTx.TxHash() - commitTxHash = bobChannel.channelState.LocalCommitment.CommitTx.TxHash() + commitTxHash = + bobChannel.channelState.Commitments.Local.CommitTx.TxHash() if !bytes.Equal(closeTxHash[:], commitTxHash[:]) { t.Fatalf("bob: incorrect close transaction txid") } @@ -1401,7 +1404,8 @@ func TestDustHTLCFees(t *testing.T) { ) require.NoError(t, err, "unable to create test channels") - aliceStartingBalance := aliceChannel.channelState.LocalCommitment.LocalBalance + aliceStartingBalance := + aliceChannel.channelState.Commitments.Local.LocalBalance // This HTLC amount should be lower than the dust limits of both nodes. htlcAmount := lnwire.NewMSatFromSatoshis(100) @@ -1415,17 +1419,19 @@ func TestDustHTLCFees(t *testing.T) { // properly. Namely, the local+remote+commitfee values should add up to // the total capacity of the channel. This same should hold for both // sides. - totalSatoshisAlice := (aliceChannel.channelState.LocalCommitment.LocalBalance + - aliceChannel.channelState.LocalCommitment.RemoteBalance + - lnwire.NewMSatFromSatoshis(aliceChannel.channelState.LocalCommitment.CommitFee)) + aliceChanState := &aliceChannel.channelState.Commitments.Local + totalSatoshisAlice := aliceChanState.LocalBalance + + aliceChanState.RemoteBalance + + lnwire.NewMSatFromSatoshis(aliceChanState.CommitFee) if totalSatoshisAlice+htlcAmount != lnwire.NewMSatFromSatoshis(aliceChannel.Capacity) { t.Fatalf("alice's funds leaked: total satoshis are %v, but channel "+ "capacity is %v", int64(totalSatoshisAlice), int64(aliceChannel.Capacity)) } - totalSatoshisBob := (bobChannel.channelState.LocalCommitment.LocalBalance + - bobChannel.channelState.LocalCommitment.RemoteBalance + - lnwire.NewMSatFromSatoshis(bobChannel.channelState.LocalCommitment.CommitFee)) + bobChanState := bobChannel.channelState.Commitments.Local + totalSatoshisBob := bobChanState.LocalBalance + + bobChanState.RemoteBalance + + lnwire.NewMSatFromSatoshis(bobChanState.CommitFee) if totalSatoshisBob+htlcAmount != lnwire.NewMSatFromSatoshis(bobChannel.Capacity) { t.Fatalf("bob's funds leaked: total satoshis are %v, but channel "+ "capacity is %v", int64(totalSatoshisBob), @@ -1435,20 +1441,20 @@ func TestDustHTLCFees(t *testing.T) { // The commitment fee paid should be the same, as there have been no // new material outputs added. defaultFee := calcStaticFee(channeldb.SingleFunderTweaklessBit, 0) - if aliceChannel.channelState.LocalCommitment.CommitFee != defaultFee { + if aliceChanState.CommitFee != defaultFee { t.Fatalf("dust htlc amounts not subtracted from commitment fee "+ "expected %v, got %v", defaultFee, - aliceChannel.channelState.LocalCommitment.CommitFee) + aliceChanState.CommitFee) } - if bobChannel.channelState.LocalCommitment.CommitFee != defaultFee { + if bobChanState.CommitFee != defaultFee { t.Fatalf("dust htlc amounts not subtracted from commitment fee "+ "expected %v, got %v", defaultFee, - bobChannel.channelState.LocalCommitment.CommitFee) + bobChanState.CommitFee) } // Alice's final balance should reflect the HTLC deficit even though // the HTLC was paid to fees as it was trimmed. - aliceEndBalance := aliceChannel.channelState.LocalCommitment.LocalBalance + aliceEndBalance := aliceChanState.LocalBalance aliceExpectedBalance := aliceStartingBalance - htlcAmount if aliceEndBalance != aliceExpectedBalance { t.Fatalf("alice not credited for dust: expected %v, got %v", @@ -1477,7 +1483,7 @@ func TestHTLCDustLimit(t *testing.T) { htlcSat := (btcutil.Amount(500) + HtlcTimeoutFee( aliceChannel.channelState.ChanType, chainfee.SatPerKWeight( - aliceChannel.channelState.LocalCommitment.FeePerKw, + aliceChannel.channelState.Commitments.Local.FeePerKw, ), )) htlcAmount := lnwire.NewMSatFromSatoshis(htlcSat) @@ -1506,10 +1512,10 @@ func TestHTLCDustLimit(t *testing.T) { 2, len(bobCommitment.txn.TxOut)) } defaultFee := calcStaticFee(channeldb.SingleFunderTweaklessBit, 0) - if bobChannel.channelState.LocalCommitment.CommitFee != defaultFee { + if bobChannel.channelState.Commitments.Local.CommitFee != defaultFee { t.Fatalf("dust htlc amount was subtracted from commitment fee "+ "expected %v, got %v", defaultFee, - bobChannel.channelState.LocalCommitment.CommitFee) + bobChannel.channelState.Commitments.Local.CommitFee) } // Settle HTLC and create a new commitment state. @@ -1717,12 +1723,12 @@ func TestChannelBalanceDustLimit(t *testing.T) { // once fees have been subtracted, but smaller than Bob's dust limit. // We account in fees for the HTLC we will be adding. defaultFee := calcStaticFee(channeldb.SingleFunderTweaklessBit, 1) - aliceBalance := aliceChannel.channelState.LocalCommitment.LocalBalance.ToSatoshis() + aliceBalance := aliceChannel.channelState.Commitments.Local.LocalBalance.ToSatoshis() //nolint:lll htlcSat := aliceBalance - defaultFee htlcSat += HtlcSuccessFee( aliceChannel.channelState.ChanType, chainfee.SatPerKWeight( - aliceChannel.channelState.LocalCommitment.FeePerKw, + aliceChannel.channelState.Commitments.Local.FeePerKw, ), ) @@ -2129,11 +2135,12 @@ func TestCancelHTLC(t *testing.T) { // of the new HTLC. aliceExpectedBalance := btcutil.Amount(btcutil.SatoshiPerBitcoin*4) - calcStaticFee(channeldb.SingleFunderTweaklessBit, 1) - if aliceChannel.channelState.LocalCommitment.LocalBalance.ToSatoshis() != + aliceChanState := &aliceChannel.channelState.Commitments.Local + if aliceChanState.LocalBalance.ToSatoshis() != aliceExpectedBalance { t.Fatalf("Alice's balance is wrong: expected %v, got %v", aliceExpectedBalance, - aliceChannel.channelState.LocalCommitment.LocalBalance.ToSatoshis()) + aliceChanState.LocalBalance.ToSatoshis()) } // Now, with the HTLC committed on both sides, trigger a cancellation @@ -2174,32 +2181,33 @@ func TestCancelHTLC(t *testing.T) { expectedBalance := btcutil.Amount(btcutil.SatoshiPerBitcoin * 5) staticFee := calcStaticFee(channeldb.SingleFunderTweaklessBit, 0) - if aliceChannel.channelState.LocalCommitment.LocalBalance.ToSatoshis() != + if aliceChanState.LocalBalance.ToSatoshis() != expectedBalance-staticFee { t.Fatalf("balance is wrong: expected %v, got %v", - aliceChannel.channelState.LocalCommitment.LocalBalance.ToSatoshis(), + aliceChanState.LocalBalance.ToSatoshis(), expectedBalance-staticFee) } - if aliceChannel.channelState.LocalCommitment.RemoteBalance.ToSatoshis() != + if aliceChanState.RemoteBalance.ToSatoshis() != expectedBalance { t.Fatalf("balance is wrong: expected %v, got %v", - aliceChannel.channelState.LocalCommitment.RemoteBalance.ToSatoshis(), + aliceChanState.RemoteBalance.ToSatoshis(), expectedBalance) } - if bobChannel.channelState.LocalCommitment.LocalBalance.ToSatoshis() != + bobChanState := bobChannel.channelState.Commitments.Local + if bobChanState.LocalBalance.ToSatoshis() != expectedBalance { t.Fatalf("balance is wrong: expected %v, got %v", - bobChannel.channelState.LocalCommitment.LocalBalance.ToSatoshis(), + bobChanState.LocalBalance.ToSatoshis(), expectedBalance) } - if bobChannel.channelState.LocalCommitment.RemoteBalance.ToSatoshis() != + if bobChanState.RemoteBalance.ToSatoshis() != expectedBalance-staticFee { t.Fatalf("balance is wrong: expected %v, got %v", - bobChannel.channelState.LocalCommitment.RemoteBalance.ToSatoshis(), + bobChanState.RemoteBalance.ToSatoshis(), expectedBalance-staticFee) } } @@ -2216,10 +2224,10 @@ func TestCooperativeCloseDustAdherence(t *testing.T) { require.NoError(t, err, "unable to create test channels") aliceFeeRate := chainfee.SatPerKWeight( - aliceChannel.channelState.LocalCommitment.FeePerKw, + aliceChannel.channelState.Commitments.Local.FeePerKw, ) bobFeeRate := chainfee.SatPerKWeight( - bobChannel.channelState.LocalCommitment.FeePerKw, + bobChannel.channelState.Commitments.Local.FeePerKw, ) setDustLimit := func(dustVal btcutil.Amount) { @@ -2235,10 +2243,12 @@ func TestCooperativeCloseDustAdherence(t *testing.T) { } setBalances := func(aliceBalance, bobBalance lnwire.MilliSatoshi) { - aliceChannel.channelState.LocalCommitment.LocalBalance = aliceBalance - aliceChannel.channelState.LocalCommitment.RemoteBalance = bobBalance - bobChannel.channelState.LocalCommitment.LocalBalance = bobBalance - bobChannel.channelState.LocalCommitment.RemoteBalance = aliceBalance + aliceChanState := &aliceChannel.channelState.Commitments.Local + aliceChanState.LocalBalance = aliceBalance + aliceChanState.RemoteBalance = bobBalance + bobChanState := &bobChannel.channelState.Commitments.Local + bobChanState.LocalBalance = bobBalance + bobChanState.RemoteBalance = aliceBalance } aliceDeliveryScript := bobsPrivKey[:] @@ -2309,7 +2319,7 @@ func TestCooperativeCloseDustAdherence(t *testing.T) { t.Fatalf("close tx has wrong number of outputs: expected %v "+ "got %v", 1, len(closeTx.TxOut)) } - commitFee := aliceChannel.channelState.LocalCommitment.CommitFee + commitFee := aliceChannel.channelState.Commitments.Local.CommitFee aliceExpectedBalance := aliceBal.ToSatoshis() - aliceFee + commitFee if closeTx.TxOut[0].Value != int64(aliceExpectedBalance) { t.Fatalf("alice's balance is incorrect: expected %v, got %v", @@ -2379,7 +2389,7 @@ func TestUpdateFeeAdjustments(t *testing.T) { // First, we'll grab the current base fee rate as we'll be using this // to make relative adjustments int he fee rate. - baseFeeRate := aliceChannel.channelState.LocalCommitment.FeePerKw + baseFeeRate := aliceChannel.channelState.Commitments.Local.FeePerKw // We'll first try to increase the fee rate 5x, this should be able to // be committed without any issue. @@ -2504,7 +2514,9 @@ func TestUpdateFeeConcurrentSig(t *testing.T) { err = bobChannel.ReceiveNewCommitment(aliceNewCommits.CommitSigs) require.NoError(t, err, "bob unable to process alice's new commitment") - if chainfee.SatPerKWeight(bobChannel.channelState.LocalCommitment.FeePerKw) == fee { + if chainfee.SatPerKWeight( + bobChannel.channelState.Commitments.Local.FeePerKw, + ) == fee { t.Fatalf("bob's feePerKw was unexpectedly locked in") } @@ -2513,7 +2525,9 @@ func TestUpdateFeeConcurrentSig(t *testing.T) { _, _, _, err = bobChannel.RevokeCurrentCommitment() require.NoError(t, err, "unable to generate bob revocation") - if chainfee.SatPerKWeight(bobChannel.channelState.LocalCommitment.FeePerKw) != fee { + if chainfee.SatPerKWeight( + bobChannel.channelState.Commitments.Local.FeePerKw, + ) != fee { t.Fatalf("bob's feePerKw was not locked in") } } @@ -2563,7 +2577,7 @@ func TestUpdateFeeSenderCommits(t *testing.T) { require.NoError(t, err, "bob unable to process alice's new commitment") if chainfee.SatPerKWeight( - bobChannel.channelState.LocalCommitment.FeePerKw, + bobChannel.channelState.Commitments.Local.FeePerKw, ) == fee { t.Fatalf("bob's feePerKw was unexpectedly locked in") @@ -2575,7 +2589,7 @@ func TestUpdateFeeSenderCommits(t *testing.T) { require.NoError(t, err, "unable to generate bob revocation") if chainfee.SatPerKWeight( - bobChannel.channelState.LocalCommitment.FeePerKw, + bobChannel.channelState.Commitments.Local.FeePerKw, ) != fee { t.Fatalf("bob's feePerKw was not locked in") @@ -2598,7 +2612,7 @@ func TestUpdateFeeSenderCommits(t *testing.T) { require.NoError(t, err, "alice unable to process bob's new commitment") if chainfee.SatPerKWeight( - aliceChannel.channelState.LocalCommitment.FeePerKw, + aliceChannel.channelState.Commitments.Local.FeePerKw, ) == fee { t.Fatalf("alice's feePerKw was unexpectedly locked in") @@ -2610,7 +2624,7 @@ func TestUpdateFeeSenderCommits(t *testing.T) { require.NoError(t, err, "unable to revoke alice channel") if chainfee.SatPerKWeight( - aliceChannel.channelState.LocalCommitment.FeePerKw, + aliceChannel.channelState.Commitments.Local.FeePerKw, ) != fee { t.Fatalf("alice's feePerKw was not locked in") @@ -2687,7 +2701,7 @@ func TestUpdateFeeReceiverCommits(t *testing.T) { require.NoError(t, err, "alice unable to process bob's new commitment") if chainfee.SatPerKWeight( - bobChannel.channelState.LocalCommitment.FeePerKw, + bobChannel.channelState.Commitments.Local.FeePerKw, ) == fee { t.Fatalf("bob's feePerKw was unexpectedly locked in") @@ -2700,7 +2714,7 @@ func TestUpdateFeeReceiverCommits(t *testing.T) { require.NoError(t, err, "unable to revoke alice channel") if chainfee.SatPerKWeight( - bobChannel.channelState.LocalCommitment.FeePerKw, + bobChannel.channelState.Commitments.Local.FeePerKw, ) != fee { t.Fatalf("bob's feePerKw was not locked in") @@ -2722,7 +2736,7 @@ func TestUpdateFeeReceiverCommits(t *testing.T) { require.NoError(t, err, "alice unable to process bob's new commitment") if chainfee.SatPerKWeight( - aliceChannel.channelState.LocalCommitment.FeePerKw, + aliceChannel.channelState.Commitments.Local.FeePerKw, ) == fee { t.Fatalf("alice's feePerKw was unexpectedly locked in") @@ -2734,7 +2748,7 @@ func TestUpdateFeeReceiverCommits(t *testing.T) { require.NoError(t, err, "unable to generate bob revocation") if chainfee.SatPerKWeight( - aliceChannel.channelState.LocalCommitment.FeePerKw, + aliceChannel.channelState.Commitments.Local.FeePerKw, ) != fee { t.Fatalf("Alice's feePerKw was not locked in") @@ -2812,7 +2826,7 @@ func TestUpdateFeeMultipleUpdates(t *testing.T) { require.NoError(t, err, "bob unable to process alice's new commitment") if chainfee.SatPerKWeight( - bobChannel.channelState.LocalCommitment.FeePerKw, + bobChannel.channelState.Commitments.Local.FeePerKw, ) == fee { t.Fatalf("bob's feePerKw was unexpectedly locked in") @@ -2836,7 +2850,7 @@ func TestUpdateFeeMultipleUpdates(t *testing.T) { require.NoError(t, err, "unable to generate bob revocation") if chainfee.SatPerKWeight( - bobChannel.channelState.LocalCommitment.FeePerKw, + bobChannel.channelState.Commitments.Local.FeePerKw, ) != fee { t.Fatalf("bob's feePerKw was not locked in") @@ -2861,7 +2875,7 @@ func TestUpdateFeeMultipleUpdates(t *testing.T) { } if chainfee.SatPerKWeight( - aliceChannel.channelState.LocalCommitment.FeePerKw, + aliceChannel.channelState.Commitments.Local.FeePerKw, ) == fee { t.Fatalf("alice's feePerKw was unexpectedly locked in") @@ -2873,7 +2887,7 @@ func TestUpdateFeeMultipleUpdates(t *testing.T) { require.NoError(t, err, "unable to revoke alice channel") if chainfee.SatPerKWeight( - aliceChannel.channelState.LocalCommitment.FeePerKw, + aliceChannel.channelState.Commitments.Local.FeePerKw, ) != fee { t.Fatalf("alice's feePerKw was not locked in") @@ -4734,7 +4748,7 @@ func TestFeeUpdateRejectInsaneFee(t *testing.T) { // Next, we'll try to add a fee rate to Alice which is 1,000,000x her // starting fee rate. startingFeeRate := chainfee.SatPerKWeight( - aliceChannel.channelState.LocalCommitment.FeePerKw, + aliceChannel.channelState.Commitments.Local.FeePerKw, ) newFeeRate := startingFeeRate * 1000000 @@ -4761,7 +4775,7 @@ func TestChannelRetransmissionFeeUpdate(t *testing.T) { // First, we'll fetch the current fee rate present within the // commitment transactions. startingFeeRate := chainfee.SatPerKWeight( - aliceChannel.channelState.LocalCommitment.FeePerKw, + aliceChannel.channelState.Commitments.Local.FeePerKw, ) // Next, we'll start a commitment update, with Alice sending a new @@ -4877,13 +4891,13 @@ func TestChannelRetransmissionFeeUpdate(t *testing.T) { // Both parties should now have the latest fee rate locked-in. if chainfee.SatPerKWeight( - aliceChannel.channelState.LocalCommitment.FeePerKw, + aliceChannel.channelState.Commitments.Local.FeePerKw, ) != newFeeRate { t.Fatalf("alice's feePerKw was not locked in") } if chainfee.SatPerKWeight( - bobChannel.channelState.LocalCommitment.FeePerKw, + bobChannel.channelState.Commitments.Local.FeePerKw, ) != newFeeRate { t.Fatalf("bob's feePerKw was not locked in") @@ -4961,7 +4975,7 @@ func TestFeeUpdateOldDiskFormat(t *testing.T) { // First, we'll fetch the current fee rate present within the // commitment transactions. startingFeeRate := chainfee.SatPerKWeight( - aliceChannel.channelState.LocalCommitment.FeePerKw, + aliceChannel.channelState.Commitments.Local.FeePerKw, ) newFeeRate := startingFeeRate @@ -5065,13 +5079,13 @@ func TestFeeUpdateOldDiskFormat(t *testing.T) { // Both parties should now have the latest fee rate locked-in. if chainfee.SatPerKWeight( - aliceChannel.channelState.LocalCommitment.FeePerKw, + aliceChannel.channelState.Commitments.Local.FeePerKw, ) != newFeeRate { t.Fatalf("alice's feePerKw was not locked in") } if chainfee.SatPerKWeight( - bobChannel.channelState.LocalCommitment.FeePerKw, + bobChannel.channelState.Commitments.Local.FeePerKw, ) != newFeeRate { t.Fatalf("bob's feePerKw was not locked in") @@ -5091,13 +5105,13 @@ func TestFeeUpdateOldDiskFormat(t *testing.T) { // ...and the final fee rate locked in. if chainfee.SatPerKWeight( - aliceChannel.channelState.LocalCommitment.FeePerKw, + aliceChannel.channelState.Commitments.Local.FeePerKw, ) != newFeeRate { t.Fatalf("alice's feePerKw was not locked in") } if chainfee.SatPerKWeight( - bobChannel.channelState.LocalCommitment.FeePerKw, + bobChannel.channelState.Commitments.Local.FeePerKw, ) != newFeeRate { t.Fatalf("bob's feePerKw was not locked in") @@ -5236,7 +5250,7 @@ func TestChanAvailableBandwidth(t *testing.T) { aliceChannel.channelState.ChanCfgs.Local.ChanReserve, ) feeRate := chainfee.SatPerKWeight( - aliceChannel.channelState.LocalCommitment.FeePerKw, + aliceChannel.channelState.Commitments.Local.FeePerKw, ) assertBandwidthEstimateCorrect := func(aliceInitiate bool, @@ -5379,7 +5393,7 @@ func TestChanAvailableBalanceNearHtlcFee(t *testing.T) { aliceChannel.channelState.ChanCfgs.Local.DustLimit, ) feeRate := chainfee.SatPerKWeight( - aliceChannel.channelState.LocalCommitment.FeePerKw, + aliceChannel.channelState.Commitments.Local.FeePerKw, ) // When calculating the fee buffer sending an htlc we need to account @@ -5392,7 +5406,7 @@ func TestChanAvailableBalanceNearHtlcFee(t *testing.T) { feeRate.FeeForWeight(input.HTLCWeight), ) commitFee := lnwire.NewMSatFromSatoshis( - aliceChannel.channelState.LocalCommitment.CommitFee, + aliceChannel.channelState.Commitments.Local.CommitFee, ) htlcTimeoutFee := lnwire.NewMSatFromSatoshis( HtlcTimeoutFee(aliceChannel.channelState.ChanType, feeRate), @@ -5563,7 +5577,7 @@ func TestChanCommitWeightDustHtlcs(t *testing.T) { ) feeRate := chainfee.SatPerKWeight( - aliceChannel.channelState.LocalCommitment.FeePerKw, + aliceChannel.channelState.Commitments.Local.FeePerKw, ) htlcTimeoutFee := lnwire.NewMSatFromSatoshis( HtlcTimeoutFee(aliceChannel.channelState.ChanType, feeRate), @@ -5643,7 +5657,8 @@ func TestChanCommitWeightDustHtlcs(t *testing.T) { // In addition, we expect this weight to result in the fee we currently // see being paid on the remote commitent. calcFee := feeRate.FeeForWeight(weight2) - remoteCommitFee := aliceChannel.channelState.RemoteCommitment.CommitFee + remoteCommitFee := + aliceChannel.channelState.Commitments.Remote.CommitFee require.Equal(t, calcFee, remoteCommitFee) // Settle the HTLC, bringing commitment weight back to base. @@ -5665,7 +5680,7 @@ func TestChanCommitWeightDustHtlcs(t *testing.T) { // Ensure the current remote commit has the expected commitfee. calcFee = feeRate.FeeForWeight(weight2) - remoteCommitFee = bobChannel.channelState.RemoteCommitment.CommitFee + remoteCommitFee = bobChannel.channelState.Commitments.Remote.CommitFee require.Equal(t, calcFee, remoteCommitFee) settleHtlc(preimg) @@ -6093,7 +6108,7 @@ func TestChannelUnilateralCloseHtlcResolution(t *testing.T) { aliceCloseSummary, err := NewUnilateralCloseSummary( aliceChannel.channelState, aliceChannel.Signer, spendDetail, - aliceChannel.channelState.RemoteCommitment, + aliceChannel.channelState.Commitments.Remote, aliceChannel.channelState.RemoteCurrentRevocation, fn.Some[AuxLeafStore](&MockAuxLeafStore{}), fn.Some[AuxContractResolver](&MockAuxContractResolver{}), @@ -6239,7 +6254,7 @@ func TestChannelUnilateralClosePendingCommit(t *testing.T) { aliceWrongCloseSummary, err := NewUnilateralCloseSummary( aliceChannel.channelState, aliceChannel.Signer, spendDetail, - aliceChannel.channelState.RemoteCommitment, + aliceChannel.channelState.Commitments.Remote, aliceChannel.channelState.RemoteCurrentRevocation, fn.Some[AuxLeafStore](&MockAuxLeafStore{}), fn.Some[AuxContractResolver](&MockAuxContractResolver{}), @@ -6640,8 +6655,10 @@ func assertChannelBalances(t *testing.T, alice, bob *LightningChannel, _, _, line, _ := runtime.Caller(1) - aliceSelfBalance := alice.channelState.LocalCommitment.LocalBalance.ToSatoshis() - aliceBobBalance := alice.channelState.LocalCommitment.RemoteBalance.ToSatoshis() + aliceSelfBalance := + alice.channelState.Commitments.Local.LocalBalance.ToSatoshis() + aliceBobBalance := + alice.channelState.Commitments.Local.RemoteBalance.ToSatoshis() if aliceSelfBalance != aliceBalance { t.Fatalf("line #%v: wrong alice self balance: expected %v, got %v", line, aliceBalance, aliceSelfBalance) @@ -6651,8 +6668,10 @@ func assertChannelBalances(t *testing.T, alice, bob *LightningChannel, line, bobBalance, aliceBobBalance) } - bobSelfBalance := bob.channelState.LocalCommitment.LocalBalance.ToSatoshis() - bobAliceBalance := bob.channelState.LocalCommitment.RemoteBalance.ToSatoshis() + bobSelfBalance := + bob.channelState.Commitments.Local.LocalBalance.ToSatoshis() + bobAliceBalance := + bob.channelState.Commitments.Local.RemoteBalance.ToSatoshis() if bobSelfBalance != bobBalance { t.Fatalf("line #%v: wrong bob self balance: expected %v, got %v", line, bobBalance, bobSelfBalance) @@ -6731,7 +6750,7 @@ func TestChanReserve(t *testing.T) { t.Fatalf("unable to complete state update: %v", err) } - commitFee := aliceChannel.channelState.LocalCommitment.CommitFee + commitFee := aliceChannel.channelState.Commitments.Local.CommitFee assertChannelBalances( t, aliceChannel, bobChannel, btcutil.SatoshiPerBitcoin*4.5-commitFee, btcutil.SatoshiPerBitcoin*5, @@ -6808,7 +6827,7 @@ func TestChanReserve(t *testing.T) { t.Fatalf("unable to complete state update: %v", err) } - commitFee = aliceChannel.channelState.LocalCommitment.CommitFee + commitFee = aliceChannel.channelState.Commitments.Local.CommitFee assertChannelBalances( t, aliceChannel, bobChannel, btcutil.SatoshiPerBitcoin*3-commitFee, btcutil.SatoshiPerBitcoin*5, @@ -6824,7 +6843,7 @@ func TestChanReserve(t *testing.T) { t.Fatalf("unable to complete state update: %v", err) } - commitFee = aliceChannel.channelState.LocalCommitment.CommitFee + commitFee = aliceChannel.channelState.Commitments.Local.CommitFee assertChannelBalances( t, aliceChannel, bobChannel, btcutil.SatoshiPerBitcoin*3-commitFee, btcutil.SatoshiPerBitcoin*7, @@ -6843,7 +6862,7 @@ func TestChanReserve(t *testing.T) { t.Fatalf("unable to complete state update: %v", err) } - commitFee = aliceChannel.channelState.LocalCommitment.CommitFee + commitFee = aliceChannel.channelState.Commitments.Local.CommitFee assertChannelBalances( t, aliceChannel, bobChannel, btcutil.SatoshiPerBitcoin*3-commitFee, btcutil.SatoshiPerBitcoin*6, @@ -6869,7 +6888,7 @@ func TestChanReserveRemoteInitiator(t *testing.T) { // to add any more HTLCs to the commitment. Although a reserve this // high is unrealistic, a channel can easily get into a situation // where the initiator cannot pay for the fee of any more HTLCs. - commitFee := aliceChannel.channelState.LocalCommitment.CommitFee + commitFee := aliceChannel.channelState.Commitments.Local.CommitFee aliceMinReserve := 5*btcutil.SatoshiPerBitcoin - commitFee aliceChannel.channelState.ChanCfgs.Local.ChanReserve = aliceMinReserve @@ -6917,14 +6936,14 @@ func TestChanReserveLocalInitiatorDustHtlc(t *testing.T) { htlcSat := btcutil.Amount(500) + HtlcTimeoutFee( aliceChannel.channelState.ChanType, chainfee.SatPerKWeight( - aliceChannel.channelState.LocalCommitment.FeePerKw, + aliceChannel.channelState.Commitments.Local.FeePerKw, ), ) // Set Alice's channel reserve to be low enough to carry the value of // the HTLC, but not low enough to allow the extra fee from adding the // HTLC to the commitment. - commitFee := aliceChannel.channelState.LocalCommitment.CommitFee + commitFee := aliceChannel.channelState.Commitments.Local.CommitFee aliceMinReserve := 5*btcutil.SatoshiPerBitcoin - commitFee - htlcSat aliceChannel.channelState.ChanCfgs.Local.ChanReserve = aliceMinReserve @@ -7073,7 +7092,8 @@ func TestNewBreachRetributionSkipsDustHtlcs(t *testing.T) { // At this point, we'll capture the current state number, as well as // the current commitment. - revokedStateNum := aliceChannel.channelState.LocalCommitment.CommitHeight + revokedStateNum := + aliceChannel.channelState.Commitments.Local.CommitHeight // We'll now have Bob settle those HTLC's to Alice and then advance // forward to a new state. @@ -7093,7 +7113,7 @@ func TestNewBreachRetributionSkipsDustHtlcs(t *testing.T) { // At this point, we'll now simulate a contract breach by Bob using the // NewBreachRetribution method. - breachTx := aliceChannel.channelState.RemoteCommitment.CommitTx + breachTx := aliceChannel.channelState.Commitments.Remote.CommitTx breachRet, err := NewBreachRetribution( aliceChannel.channelState, revokedStateNum, 100, breachTx, fn.Some[AuxLeafStore](&MockAuxLeafStore{}), @@ -7977,7 +7997,7 @@ func TestChannelMaxFeeRate(t *testing.T) { ) currentFeeRate := chainfee.SatPerKWeight( - tc.channel.channelState.LocalCommitment.FeePerKw, + tc.channel.channelState.Commitments.Local.FeePerKw, ) // When the fee allocation would push our max fee rate below our @@ -9691,7 +9711,7 @@ func deriveDummyRetributionParams(chanState *channeldb.OpenChannel) (uint32, *CommitmentKeyRing, chainhash.Hash) { config := chanState.ChanCfgs.Remote - commitHash := chanState.RemoteCommitment.CommitTx.TxHash() + commitHash := chanState.Commitments.Remote.CommitTx.TxHash() keyRing := DeriveCommitmentKeys( config.RevocationBasePoint.PubKey, lntypes.Remote, chanState.ChanType, &chanState.ChanCfgs.Local, @@ -9981,7 +10001,7 @@ func TestCreateBreachRetributionLegacy(t *testing.T) { ) // Use the remote commitment as our revocation log. - revokedLog := aliceChannel.channelState.RemoteCommitment + revokedLog := aliceChannel.channelState.Commitments.Remote ourOp := revokedLog.CommitTx.TxOut[0] theirOp := revokedLog.CommitTx.TxOut[1] @@ -10052,7 +10072,7 @@ func testNewBreachRetribution(t *testing.T, chanType channeldb.ChannelType) { stateNum := uint64(0) chainHash := aliceChannel.channelState.ChainHash theirDelay := uint32(aliceChannel.channelState.ChanCfgs.Remote.CsvDelay) - breachTx := aliceChannel.channelState.RemoteCommitment.CommitTx + breachTx := aliceChannel.channelState.Commitments.Remote.CommitTx // Create a breach retribution at height 0, which should give us an // error as there are no past delta state saved as revocation logs yet. @@ -10074,7 +10094,7 @@ func testNewBreachRetribution(t *testing.T, chanType channeldb.ChannelType) { // We now force a state transition which will give us a revocation log // at height 0. - txid := aliceChannel.channelState.RemoteCommitment.CommitTx.TxHash() + txid := aliceChannel.channelState.Commitments.Remote.CommitTx.TxHash() err = ForceStateTransition(aliceChannel, bobChannel) require.NoError(t, err) @@ -10418,7 +10438,7 @@ func TestAsynchronousSendingContraint(t *testing.T) { // Static fee rate of 6000 sats/kw. feePerKw := chainfee.SatPerKWeight( - aliceChannel.channelState.LocalCommitment.FeePerKw, + aliceChannel.channelState.Commitments.Local.FeePerKw, ) additionalHtlc := feePerKw.FeeForWeight(input.HTLCWeight) @@ -10551,7 +10571,7 @@ func TestAsynchronousSendingWithFeeBuffer(t *testing.T) { // Static fee rate of 6000 sats/kw. feePerKw := chainfee.SatPerKWeight( - aliceChannel.channelState.LocalCommitment.FeePerKw, + aliceChannel.channelState.Commitments.Local.FeePerKw, ) // Calculate the fee buffer for the current commitment tx including @@ -10685,7 +10705,8 @@ func TestAsynchronousSendingWithFeeBuffer(t *testing.T) { // All of alice's balance is used up in fees and htlcs so the local // balance equals exactly the local reserve. - require.Equal(t, aliceChannel.channelState.LocalCommitment.LocalBalance, + require.Equal(t, + aliceChannel.channelState.Commitments.Local.LocalBalance, lnwire.NewMSatFromSatoshis(aliceReserve)) } @@ -10742,7 +10763,7 @@ func TestEnforceFeeBuffer(t *testing.T) { // Static fee rate of 6000 sats/kw. feePerKw := chainfee.SatPerKWeight( - aliceChannel.channelState.LocalCommitment.FeePerKw, + aliceChannel.channelState.Commitments.Local.FeePerKw, ) // Commitment Fee of the channel state (with 1 pending htlc). @@ -10820,7 +10841,7 @@ func TestEnforceFeeBuffer(t *testing.T) { feeHTLCMsat := lnwire.NewMSatFromSatoshis(feeHTLC) aliceBalance := aliceReserveMsat + bufferAmt - 2*feeHTLCMsat - expectedAmt := aliceChannel.channelState.LocalCommitment.LocalBalance + expectedAmt := aliceChannel.channelState.Commitments.Local.LocalBalance require.Equal(t, aliceBalance, expectedAmt) } diff --git a/lnwallet/commitment.go b/lnwallet/commitment.go index 59d9bf54ba1..b8ff9719cf3 100644 --- a/lnwallet/commitment.go +++ b/lnwallet/commitment.go @@ -1279,7 +1279,7 @@ func findOutputIndexesFromRemote(revocationPreimage *chainhash.Hash, ourIndex := uint32(channeldb.OutputIndexEmpty) theirIndex := uint32(channeldb.OutputIndexEmpty) - chanCommit := chanState.RemoteCommitment + chanCommit := chanState.Commitments.Remote _, commitmentPoint := btcec.PrivKeyFromBytes(revocationPreimage[:]) // With the commitment point generated, we can now derive the king ring diff --git a/lnwallet/reservation.go b/lnwallet/reservation.go index 4c4f58f8be0..0f5d212d771 100644 --- a/lnwallet/reservation.go +++ b/lnwallet/reservation.go @@ -483,17 +483,23 @@ func NewChannelReservation(capacity, localFundingAmt btcutil.Amount, IsInitiator: initiator, ChannelFlags: req.Flags, Capacity: capacity, - LocalCommitment: channeldb.ChannelCommitment{ - LocalBalance: ourBalance, - RemoteBalance: theirBalance, - FeePerKw: btcutil.Amount(req.CommitFeePerKw), - CommitFee: commitFee, - }, - RemoteCommitment: channeldb.ChannelCommitment{ - LocalBalance: ourBalance, - RemoteBalance: theirBalance, - FeePerKw: btcutil.Amount(req.CommitFeePerKw), - CommitFee: commitFee, + Commitments: lntypes.Dual[channeldb.ChannelCommitment]{ + Local: channeldb.ChannelCommitment{ + LocalBalance: ourBalance, + RemoteBalance: theirBalance, + FeePerKw: btcutil.Amount( + req.CommitFeePerKw, + ), + CommitFee: commitFee, + }, + Remote: channeldb.ChannelCommitment{ + LocalBalance: ourBalance, + RemoteBalance: theirBalance, + FeePerKw: btcutil.Amount( + req.CommitFeePerKw, + ), + CommitFee: commitFee, + }, }, ThawHeight: thawHeight, Db: wallet.Cfg.Database, diff --git a/lnwallet/test_utils.go b/lnwallet/test_utils.go index 91d81623bf1..1bca0be912a 100644 --- a/lnwallet/test_utils.go +++ b/lnwallet/test_utils.go @@ -335,11 +335,13 @@ func CreateTestChannels(t *testing.T, chanType channeldb.ChannelType, RemoteCurrentRevocation: bobCommitPoint, RevocationProducer: alicePreimageProducer, RevocationStore: shachain.NewRevocationStore(), - LocalCommitment: aliceLocalCommit, - RemoteCommitment: aliceRemoteCommit, - Db: dbAlice.ChannelStateDB(), - Packager: channeldb.NewChannelPackager(shortChanID), - FundingTxn: testTx, + Commitments: lntypes.Dual[channeldb.ChannelCommitment]{ + Local: aliceLocalCommit, + Remote: aliceRemoteCommit, + }, + Db: dbAlice.ChannelStateDB(), + Packager: channeldb.NewChannelPackager(shortChanID), + FundingTxn: testTx, } bobChannelState := &channeldb.OpenChannel{ ChanCfgs: lntypes.Dual[channeldb.ChannelConfig]{ @@ -355,10 +357,12 @@ func CreateTestChannels(t *testing.T, chanType channeldb.ChannelType, RemoteCurrentRevocation: aliceCommitPoint, RevocationProducer: bobPreimageProducer, RevocationStore: shachain.NewRevocationStore(), - LocalCommitment: bobLocalCommit, - RemoteCommitment: bobRemoteCommit, - Db: dbBob.ChannelStateDB(), - Packager: channeldb.NewChannelPackager(shortChanID), + Commitments: lntypes.Dual[channeldb.ChannelCommitment]{ + Local: bobLocalCommit, + Remote: bobRemoteCommit, + }, + Db: dbBob.ChannelStateDB(), + Packager: channeldb.NewChannelPackager(shortChanID), } // If the channel type has a tapscript root, then we'll also specify diff --git a/lnwallet/transactions_test.go b/lnwallet/transactions_test.go index 847ed159490..024d74b1f9f 100644 --- a/lnwallet/transactions_test.go +++ b/lnwallet/transactions_test.go @@ -987,11 +987,13 @@ func createTestChannelsForVectors(tc *testContext, chanType channeldb.ChannelTyp RemoteCurrentRevocation: localCommitPoint, RevocationProducer: remotePreimageProducer, RevocationStore: shachain.NewRevocationStore(), - LocalCommitment: remoteCommit, - RemoteCommitment: remoteCommit, - Db: dbRemote.ChannelStateDB(), - Packager: channeldb.NewChannelPackager(shortChanID), - FundingTxn: tc.fundingTx.MsgTx(), + Commitments: lntypes.Dual[channeldb.ChannelCommitment]{ + Local: remoteCommit, + Remote: remoteCommit, + }, + Db: dbRemote.ChannelStateDB(), + Packager: channeldb.NewChannelPackager(shortChanID), + FundingTxn: tc.fundingTx.MsgTx(), } localChannelState := &channeldb.OpenChannel{ ChanCfgs: lntypes.Dual[channeldb.ChannelConfig]{ @@ -1007,11 +1009,13 @@ func createTestChannelsForVectors(tc *testContext, chanType channeldb.ChannelTyp RemoteCurrentRevocation: remoteCommitPoint, RevocationProducer: localPreimageProducer, RevocationStore: shachain.NewRevocationStore(), - LocalCommitment: localCommit, - RemoteCommitment: localCommit, - Db: dbLocal.ChannelStateDB(), - Packager: channeldb.NewChannelPackager(shortChanID), - FundingTxn: tc.fundingTx.MsgTx(), + Commitments: lntypes.Dual[channeldb.ChannelCommitment]{ + Local: localCommit, + Remote: localCommit, + }, + Db: dbLocal.ChannelStateDB(), + Packager: channeldb.NewChannelPackager(shortChanID), + FundingTxn: tc.fundingTx.MsgTx(), } // Create mock signers that can sign for the keys that are used. diff --git a/lnwallet/wallet.go b/lnwallet/wallet.go index 78f961fbfdd..898e11adfff 100644 --- a/lnwallet/wallet.go +++ b/lnwallet/wallet.go @@ -1852,13 +1852,13 @@ func (l *LightningWallet) handleChanPointReady(req *continueContributionMsg) { return desc.CustomFundingBlob })(req.auxFundingDesc) - chanState.LocalCommitment.CustomBlob = fn.MapOption( + chanState.Commitments.Local.CustomBlob = fn.MapOption( func(desc AuxFundingDesc) tlv.Blob { return desc.CustomLocalCommitBlob }, )(req.auxFundingDesc) - chanState.RemoteCommitment.CustomBlob = fn.MapOption( + chanState.Commitments.Remote.CustomBlob = fn.MapOption( func(desc AuxFundingDesc) tlv.Blob { return desc.CustomRemoteCommitBlob }, @@ -1931,8 +1931,9 @@ func (l *LightningWallet) handleChanPointReady(req *continueContributionMsg) { } // With the funding tx complete, create both commitment transactions. - localBalance := pendingReservation.partialState.LocalCommitment.LocalBalance.ToSatoshis() - remoteBalance := pendingReservation.partialState.LocalCommitment.RemoteBalance.ToSatoshis() + localCommitment := pendingReservation.partialState.Commitments.Local + localBalance := localCommitment.LocalBalance.ToSatoshis() + remoteBalance := localCommitment.RemoteBalance.ToSatoshis() var leaseExpiry uint32 if pendingReservation.partialState.ChanType.HasLeaseExpiration() { leaseExpiry = pendingReservation.partialState.ThawHeight @@ -2007,8 +2008,8 @@ func (l *LightningWallet) handleChanPointReady(req *continueContributionMsg) { // Record newly available information within the open channel state. chanState.FundingOutpoint = chanPoint - chanState.LocalCommitment.CommitTx = ourCommitTx - chanState.RemoteCommitment.CommitTx = theirCommitTx + chanState.Commitments.Local.CommitTx = ourCommitTx + chanState.Commitments.Remote.CommitTx = theirCommitTx // Next, we'll obtain the funding witness script, and the funding // output itself so we can generate a valid signature for the remote @@ -2283,7 +2284,7 @@ func (l *LightningWallet) handleFundingCounterPartySigs(msg *addCounterPartySigs // At this point, we can also record and verify their signature for our // commitment transaction. res.theirCommitmentSig = msg.theirCommitmentSig - commitTx := res.partialState.LocalCommitment.CommitTx + commitTx := res.partialState.Commitments.Local.CommitTx err := l.verifyCommitSig(res, msg.theirCommitmentSig, commitTx) if err != nil { @@ -2294,7 +2295,7 @@ func (l *LightningWallet) handleFundingCounterPartySigs(msg *addCounterPartySigs } theirCommitSigBytes := msg.theirCommitmentSig.Serialize() - res.partialState.LocalCommitment.CommitSig = theirCommitSigBytes + res.partialState.Commitments.Local.CommitSig = theirCommitSigBytes // Funding complete, this entry can be removed from limbo. l.limboMtx.Lock() @@ -2374,12 +2375,12 @@ func (l *LightningWallet) handleSingleFunderSigs(req *addSingleFunderSigsMsg) { chanState.CustomBlob = fn.MapOption(func(desc AuxFundingDesc) tlv.Blob { return desc.CustomFundingBlob })(req.auxFundingDesc) - chanState.LocalCommitment.CustomBlob = fn.MapOption( + chanState.Commitments.Local.CustomBlob = fn.MapOption( func(desc AuxFundingDesc) tlv.Blob { return desc.CustomLocalCommitBlob }, )(req.auxFundingDesc) - chanState.RemoteCommitment.CustomBlob = fn.MapOption( + chanState.Commitments.Remote.CustomBlob = fn.MapOption( func(desc AuxFundingDesc) tlv.Blob { return desc.CustomRemoteCommitBlob }, @@ -2392,8 +2393,10 @@ func (l *LightningWallet) handleSingleFunderSigs(req *addSingleFunderSigsMsg) { // Now that we have the funding outpoint, we can generate both versions // of the commitment transaction, and generate a signature for the // remote node's commitment transactions. - localBalance := pendingReservation.partialState.LocalCommitment.LocalBalance.ToSatoshis() - remoteBalance := pendingReservation.partialState.LocalCommitment.RemoteBalance.ToSatoshis() + localBalance := pendingReservation.partialState.Commitments. + Local.LocalBalance.ToSatoshis() + remoteBalance := pendingReservation.partialState.Commitments. + Local.RemoteBalance.ToSatoshis() var leaseExpiry uint32 if pendingReservation.partialState.ChanType.HasLeaseExpiration() { leaseExpiry = pendingReservation.partialState.ThawHeight @@ -2445,8 +2448,8 @@ func (l *LightningWallet) handleSingleFunderSigs(req *addSingleFunderSigsMsg) { // without further synchronization. txsort.InPlaceSort(ourCommitTx) txsort.InPlaceSort(theirCommitTx) - chanState.LocalCommitment.CommitTx = ourCommitTx - chanState.RemoteCommitment.CommitTx = theirCommitTx + chanState.Commitments.Local.CommitTx = ourCommitTx + chanState.Commitments.Remote.CommitTx = theirCommitTx walletLog.Debugf("Local commit tx for ChannelPoint(%v): %v", req.fundingOutpoint, spew.Sdump(ourCommitTx)) @@ -2465,7 +2468,7 @@ func (l *LightningWallet) handleSingleFunderSigs(req *addSingleFunderSigsMsg) { } theirCommitSigBytes := req.theirCommitmentSig.Serialize() - chanState.LocalCommitment.CommitSig = theirCommitSigBytes + chanState.Commitments.Local.CommitSig = theirCommitSigBytes channelValue := int64(pendingReservation.partialState.Capacity) theirKey := pendingReservation.theirContribution.MultiSigKey diff --git a/peer/test_utils.go b/peer/test_utils.go index 8c579df3ffb..e75bffd792e 100644 --- a/peer/test_utils.go +++ b/peer/test_utils.go @@ -257,11 +257,13 @@ func createTestPeerWithChannel(t *testing.T, updateChan func(a, RemoteCurrentRevocation: bobCommitPoint, RevocationProducer: alicePreimageProducer, RevocationStore: shachain.NewRevocationStore(), - LocalCommitment: aliceCommit, - RemoteCommitment: aliceCommit, - Db: dbAlice.ChannelStateDB(), - Packager: channeldb.NewChannelPackager(shortChanID), - FundingTxn: channels.TestFundingTx, + Commitments: lntypes.Dual[channeldb.ChannelCommitment]{ + Local: aliceCommit, + Remote: aliceCommit, + }, + Db: dbAlice.ChannelStateDB(), + Packager: channeldb.NewChannelPackager(shortChanID), + FundingTxn: channels.TestFundingTx, } bobChannelState := &channeldb.OpenChannel{ ChanCfgs: lntypes.Dual[channeldb.ChannelConfig]{ @@ -276,10 +278,12 @@ func createTestPeerWithChannel(t *testing.T, updateChan func(a, RemoteCurrentRevocation: aliceCommitPoint, RevocationProducer: bobPreimageProducer, RevocationStore: shachain.NewRevocationStore(), - LocalCommitment: bobCommit, - RemoteCommitment: bobCommit, - Db: dbBob.ChannelStateDB(), - Packager: channeldb.NewChannelPackager(shortChanID), + Commitments: lntypes.Dual[channeldb.ChannelCommitment]{ + Local: bobCommit, + Remote: bobCommit, + }, + Db: dbBob.ChannelStateDB(), + Packager: channeldb.NewChannelPackager(shortChanID), } // Set custom values on the channel states. diff --git a/pilot.go b/pilot.go index 2a37b080d08..a203f57280e 100644 --- a/pilot.go +++ b/pilot.go @@ -265,7 +265,7 @@ func initAutoPilot(svr *server, cfg *lncfg.AutoPilot, chanState := make([]autopilot.LocalChannel, len(activeChannels)) for i, channel := range activeChannels { - localCommit := channel.LocalCommitment + localCommit := channel.Commitments.Local balance := localCommit.LocalBalance.ToSatoshis() chanState[i] = autopilot.LocalChannel{ @@ -287,7 +287,7 @@ func initAutoPilot(svr *server, cfg *lncfg.AutoPilot, return nil, err } - localCommit := channel.LocalCommitment + localCommit := channel.Commitments.Local return &autopilot.LocalChannel{ ChanID: channel.ShortChanID(), Balance: localCommit.LocalBalance.ToSatoshis(), diff --git a/rpcserver.go b/rpcserver.go index 3fea4248ee8..0ec1f874b9f 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -3699,7 +3699,7 @@ func (r *rpcServer) ChannelBalance(ctx context.Context, } for _, channel := range openChannels { - c := channel.LocalCommitment + c := channel.Commitments.Local localBalance += c.LocalBalance remoteBalance += c.RemoteBalance @@ -3713,7 +3713,8 @@ func (r *rpcServer) ChannelBalance(ctx context.Context, } // Encode the custom data for this open channel. - openChanData := channel.LocalCommitment.CustomBlob.UnwrapOr(nil) + openChanData := + channel.Commitments.Local.CustomBlob.UnwrapOr(nil) err = wire.WriteVarBytes(&customDataBuf, 0, openChanData) if err != nil { return nil, err @@ -3732,12 +3733,13 @@ func (r *rpcServer) ChannelBalance(ctx context.Context, } for _, channel := range pendingChannels { - c := channel.LocalCommitment + c := channel.Commitments.Local pendingOpenLocalBalance += c.LocalBalance pendingOpenRemoteBalance += c.RemoteBalance // Encode the custom data for this pending channel. - openChanData := channel.LocalCommitment.CustomBlob.UnwrapOr(nil) + openChanData := + channel.Commitments.Local.CustomBlob.UnwrapOr(nil) err = wire.WriteVarBytes(&customDataBuf, 0, openChanData) if err != nil { return nil, err @@ -3838,7 +3840,7 @@ func (r *rpcServer) fetchPendingOpenChannels() (pendingOpenChannels, error) { witnessWeight = input.WitnessCommitmentTxWeight } - localCommitment := pendingChan.LocalCommitment + localCommitment := pendingChan.Commitments.Local utx := btcutil.NewTx(localCommitment.CommitTx) commitBaseWeight := blockchain.GetTransactionWeight(utx) commitWeight := commitBaseWeight + witnessWeight @@ -3857,11 +3859,14 @@ func (r *rpcServer) fetchPendingOpenChannels() (pendingOpenChannels, error) { result[i] = &lnrpc.PendingChannelsResponse_PendingOpenChannel{ Channel: &lnrpc.PendingChannelsResponse_PendingChannel{ - RemoteNodePub: hex.EncodeToString(pub), - ChannelPoint: pendingChan.FundingOutpoint.String(), - Capacity: int64(pendingChan.Capacity), - LocalBalance: int64(localCommitment.LocalBalance.ToSatoshis()), - RemoteBalance: int64(localCommitment.RemoteBalance.ToSatoshis()), + RemoteNodePub: hex.EncodeToString(pub), + //nolint:lll + ChannelPoint: pendingChan.FundingOutpoint.String(), + Capacity: int64(pendingChan.Capacity), + //nolint:lll + LocalBalance: int64(localCommitment.LocalBalance.ToSatoshis()), + //nolint:lll + RemoteBalance: int64(localCommitment.RemoteBalance.ToSatoshis()), //nolint:lll LocalChanReserveSat: int64(pendingChan.ChanCfgs.Local.ChanReserve), //nolint:lll @@ -3955,9 +3960,8 @@ func (r *rpcServer) fetchPendingForceCloseChannels() (pendingForceClose, } channel.NumForwardingPackages = int64(len(fwdPkgs)) - channel.RemoteBalance = int64( - historical.LocalCommitment.RemoteBalance.ToSatoshis(), - ) + //nolint:lll + channel.RemoteBalance = int64(historical.Commitments.Local.RemoteBalance.ToSatoshis()) channel.Private = isPrivate(historical) channel.Memo = string(historical.Memo) @@ -4088,24 +4092,25 @@ func (r *rpcServer) fetchWaitingCloseChannels( var commitments lnrpc.PendingChannelsResponse_Commitments // Report local commit. May not be present when DLP is active. - if waitingClose.LocalCommitment.CommitTx != nil { + if waitingClose.Commitments.Local.CommitTx != nil { commitments.LocalTxid = - waitingClose.LocalCommitment.CommitTx.TxHash(). - String() + waitingClose.Commitments.Local.CommitTx. + TxHash().String() commitments.LocalCommitFeeSat = uint64( - waitingClose.LocalCommitment.CommitFee, + waitingClose.Commitments.Local.CommitFee, ) } // Report remote commit. May not be present when DLP is active. - if waitingClose.RemoteCommitment.CommitTx != nil { + if waitingClose.Commitments.Remote.CommitTx != nil { commitments.RemoteTxid = - waitingClose.RemoteCommitment.CommitTx.TxHash(). - String() + waitingClose.Commitments.Remote.CommitTx. + TxHash().String() commitments.RemoteCommitFeeSat = uint64( - waitingClose.RemoteCommitment.CommitFee, + waitingClose.Commitments.Remote. + CommitFee, ) } @@ -4150,11 +4155,13 @@ func (r *rpcServer) fetchWaitingCloseChannels( } channel := &lnrpc.PendingChannelsResponse_PendingChannel{ - RemoteNodePub: hex.EncodeToString(pub), - ChannelPoint: chanPoint.String(), - Capacity: int64(waitingClose.Capacity), - LocalBalance: int64(waitingClose.LocalCommitment.LocalBalance.ToSatoshis()), - RemoteBalance: int64(waitingClose.LocalCommitment.RemoteBalance.ToSatoshis()), + RemoteNodePub: hex.EncodeToString(pub), + ChannelPoint: chanPoint.String(), + Capacity: int64(waitingClose.Capacity), + //nolint:lll + LocalBalance: int64(waitingClose.Commitments.Local.LocalBalance.ToSatoshis()), + //nolint:lll + RemoteBalance: int64(waitingClose.Commitments.Local.RemoteBalance.ToSatoshis()), //nolint:lll LocalChanReserveSat: int64(waitingClose.ChanCfgs.Local.ChanReserve), //nolint:lll @@ -4631,7 +4638,8 @@ func isPrivate(dbChannel *channeldb.OpenChannel) bool { // It encodes that data as a pair of var bytes blobs. func encodeCustomChanData(lnChan *channeldb.OpenChannel) ([]byte, error) { customOpenChanData := lnChan.CustomBlob.UnwrapOr(nil) - customLocalCommitData := lnChan.LocalCommitment.CustomBlob.UnwrapOr(nil) + customLocalCommitData := + lnChan.Commitments.Local.CustomBlob.UnwrapOr(nil) // Don't write any custom data if both blobs are empty. if len(customOpenChanData) == 0 && len(customLocalCommitData) == 0 { @@ -4677,7 +4685,7 @@ func createRPCOpenChannel(r *rpcServer, dbChannel *channeldb.OpenChannel, witnessWeight = input.WitnessCommitmentTxWeight } - localCommit := dbChannel.LocalCommitment + localCommit := dbChannel.Commitments.Local utx := btcutil.NewTx(localCommit.CommitTx) commitBaseWeight := blockchain.GetTransactionWeight(utx) commitWeight := commitBaseWeight + witnessWeight From 09c247a225ccf898339a7de52a42405a6500beae Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Wed, 21 Aug 2024 11:07:31 -0600 Subject: [PATCH 12/15] channeldb+contractcourt: tidy type signature for LatestCommitments --- channeldb/channel.go | 8 +++++--- contractcourt/chain_watcher.go | 16 ++++++++-------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/channeldb/channel.go b/channeldb/channel.go index d775e3abf2d..b85a8a52ac9 100644 --- a/channeldb/channel.go +++ b/channeldb/channel.go @@ -4012,7 +4012,9 @@ func (c *OpenChannel) Snapshot() *ChannelSnapshot { // remote party. These commitments are read from disk to ensure that only the // latest fully committed state is returned. The first commitment returned is // the local commitment, and the second returned is the remote commitment. -func (c *OpenChannel) LatestCommitments() (*ChannelCommitment, *ChannelCommitment, error) { +// +//nolint:lll +func (c *OpenChannel) LatestCommitments() fn.Result[*lntypes.Dual[ChannelCommitment]] { err := kvdb.View(c.Db.backend, func(tx kvdb.RTx) error { chanBucket, err := fetchChanBucket( tx, c.IdentityPub, &c.FundingOutpoint, c.ChainHash, @@ -4024,10 +4026,10 @@ func (c *OpenChannel) LatestCommitments() (*ChannelCommitment, *ChannelCommitmen return fetchChanCommitments(chanBucket, c) }, func() {}) if err != nil { - return nil, nil, err + return fn.Err[*lntypes.Dual[ChannelCommitment]](err) } - return &c.Commitments.Local, &c.Commitments.Remote, nil + return fn.Ok(&c.Commitments) } // RemoteRevocationStore returns the most up to date commitment version of the diff --git a/contractcourt/chain_watcher.go b/contractcourt/chain_watcher.go index 8a7fcf5774b..3bcf636e245 100644 --- a/contractcourt/chain_watcher.go +++ b/contractcourt/chain_watcher.go @@ -553,7 +553,7 @@ type chainSet struct { func newChainSet(chanState *channeldb.OpenChannel) (*chainSet, error) { // First, we'll grab the current unrevoked commitments for ourselves // and the remote party. - localCommit, remoteCommit, err := chanState.LatestCommitments() + commitments, err := chanState.LatestCommitments().Unpack() if err != nil { return nil, fmt.Errorf("unable to fetch channel state for "+ "chan_point=%v", chanState.FundingOutpoint) @@ -561,14 +561,14 @@ func newChainSet(chanState *channeldb.OpenChannel) (*chainSet, error) { log.Tracef("ChannelPoint(%v): local_commit_type=%v, local_commit=%v", chanState.FundingOutpoint, chanState.ChanType, - spew.Sdump(localCommit)) + spew.Sdump(commitments.Local)) log.Tracef("ChannelPoint(%v): remote_commit_type=%v, remote_commit=%v", chanState.FundingOutpoint, chanState.ChanType, - spew.Sdump(remoteCommit)) + spew.Sdump(commitments.Remote)) // Fetch the current known commit height for the remote party, and // their pending commitment chain tip if it exists. - remoteStateNum := remoteCommit.CommitHeight + remoteStateNum := commitments.Remote.CommitHeight remoteChainTip, err := chanState.RemoteCommitChainTip() if err != nil && err != channeldb.ErrNoPendingCommit { return nil, fmt.Errorf("unable to obtain chain tip for "+ @@ -581,8 +581,8 @@ func newChainSet(chanState *channeldb.OpenChannel) (*chainSet, error) { // duty. commitSet := CommitSet{ HtlcSets: map[HtlcSetKey][]channeldb.HTLC{ - LocalHtlcSet: localCommit.Htlcs, - RemoteHtlcSet: remoteCommit.Htlcs, + LocalHtlcSet: commitments.Local.Htlcs, + RemoteHtlcSet: commitments.Remote.Htlcs, }, } @@ -612,8 +612,8 @@ func newChainSet(chanState *channeldb.OpenChannel) (*chainSet, error) { return &chainSet{ remoteStateNum: remoteStateNum, commitSet: commitSet, - localCommit: *localCommit, - remoteCommit: *remoteCommit, + localCommit: commitments.Local, + remoteCommit: commitments.Remote, remotePendingCommit: remotePendingCommit, }, nil } From 9786ad6897a909279ae09feb0b0e27f0d7d15ced Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Wed, 21 Aug 2024 11:42:25 -0600 Subject: [PATCH 13/15] channeldb: add ChannelEpochs component for historical params --- channeldb/channel_epochs.go | 387 ++++++++++++++++++++++++++++++++++++ lntypes/channel_party.go | 24 +++ 2 files changed, 411 insertions(+) create mode 100644 channeldb/channel_epochs.go diff --git a/channeldb/channel_epochs.go b/channeldb/channel_epochs.go new file mode 100644 index 00000000000..8c35880bcf7 --- /dev/null +++ b/channeldb/channel_epochs.go @@ -0,0 +1,387 @@ +package channeldb + +import ( + "io" + + "github.com/btcsuite/btcd/btcutil" + "github.com/lightningnetwork/lnd/fn" + "github.com/lightningnetwork/lnd/lntypes" + "github.com/lightningnetwork/lnd/tlv" +) + +// CommitChainEpoch refers to a single period of time where a particular set +// of commitment parameters are in effect. +type CommitChainEpoch struct { + // LastHeight is the last commit height that marks the end of this + // epoch. + LastHeight uint64 + + // normalizedParams are the commitment parameters that affect the + // rendering of the commitment transaction. They are referred to as + // "normalized" because they indicate the parameters that actually + // apply to the party in question, irrespective of which party specified + // the parameter. + normalizedParams CommitmentParams +} + +// encode encodes a CommitChainEpoch to a writer. +func (c CommitChainEpoch) encode(w io.Writer) error { + return WriteElements( + w, c.LastHeight, c.normalizedParams.DustLimit, + c.normalizedParams.CsvDelay, + ) +} + +// decodeCommitChainEpoch decodes a CommitChainEpoch from a reader. +func decodeCommitChainEpoch(r io.Reader) (CommitChainEpoch, error) { + var lastHeight uint64 + var dustLimit btcutil.Amount + var csvDelay uint16 + + err := ReadElements(r, &lastHeight, &dustLimit, &csvDelay) + if err != nil { + return CommitChainEpoch{}, err + } + + return CommitChainEpoch{ + LastHeight: lastHeight, + normalizedParams: CommitmentParams{ + DustLimit: dustLimit, + CsvDelay: csvDelay, + }, + }, nil +} + +// CommitChainEpochHistory is a data structure designed to maintain the +// CommitmentParams history of both commitment chains. +type CommitChainEpochHistory struct { + // normalizedCurrent is the current commitment parameters that are + // in effect. They are separate from the history because we do not + // yet have the final heights that close these epochs out. + normalizedCurrent lntypes.Dual[CommitmentParams] + + // historical is a pair of lists of CommitChainEpochs that are sorted + // by LastHeight. + historical lntypes.Dual[[]CommitChainEpoch] +} + +// Size returns the size of the CommitChainEpochHistory in bytes. +func (c *CommitChainEpochHistory) Size() uint64 { + commitParamSize := uint64(2 * 8) // DustLimit + CsvDelay + epochSize := uint64(8) + commitParamSize + + currentSize := 2 * commitParamSize + localHistorySize := 2 + uint64(len(c.historical.Local))*epochSize + remoteHistorySize := 2 + uint64(len(c.historical.Remote))*epochSize + + return currentSize + localHistorySize + remoteHistorySize +} + +// encode encodes a CommitChainEpochHistory to a writer. +func (c *CommitChainEpochHistory) encode(w io.Writer) error { + // Write the normalized current params, always writing local before + // remote and dust limit before csv delay. + err := WriteElements( + w, c.normalizedCurrent.Local.DustLimit, + c.normalizedCurrent.Local.CsvDelay, + c.normalizedCurrent.Remote.DustLimit, + c.normalizedCurrent.Remote.CsvDelay, + ) + if err != nil { + return err + } + + // Write the length so we can handle deserialization. + err = WriteElement(w, uint16(len(c.historical.Local))) + if err != nil { + return err + } + + // Write the local epochs. + for _, epoch := range c.historical.Local { + err = epoch.encode(w) + if err != nil { + return err + } + } + + // Write the length so we can handle deserialization. + err = WriteElement(w, uint16(len(c.historical.Remote))) + if err != nil { + return err + } + + // Write the remote epochs. + for _, epoch := range c.historical.Remote { + err = epoch.encode(w) + if err != nil { + return err + } + } + + return nil +} + +// ECommitChainEpochHistory defines a tlv encoder for CommitChainEpochHistory. +func ECommitChainEpochHistory(w io.Writer, val interface{}, + buf *[8]byte) error { + + if hist, ok := val.(*CommitChainEpochHistory); ok { + return hist.encode(w) + } + + return tlv.NewTypeForEncodingErr(val, "*CommitChainEpochHistory") +} + +// decodeCommitChainEpochHistory decodes a CommitChainEpochHistory from a +// reader. +func decodeCommitChainEpochHistory(r io.Reader) (CommitChainEpochHistory, + error) { + + var normalizedCurrent lntypes.Dual[CommitmentParams] + err := ReadElements(r, &normalizedCurrent.Local.DustLimit, + &normalizedCurrent.Local.CsvDelay, + &normalizedCurrent.Remote.DustLimit, + &normalizedCurrent.Remote.CsvDelay, + ) + if err != nil { + return CommitChainEpochHistory{}, err + } + + historical := lntypes.Dual[[]CommitChainEpoch]{} + + var localEpochsLen uint16 + err = ReadElement(r, &localEpochsLen) + if err != nil { + return CommitChainEpochHistory{}, err + } + + if localEpochsLen > 0 { + historical.Local = make([]CommitChainEpoch, localEpochsLen) + for i := range historical.Local { + historical.Local[i], err = decodeCommitChainEpoch(r) + if err != nil { + return CommitChainEpochHistory{}, err + } + } + } + + var remoteEpochsLen uint16 + err = ReadElement(r, &remoteEpochsLen) + if err != nil { + return CommitChainEpochHistory{}, err + } + + if remoteEpochsLen > 0 { + historical.Remote = make([]CommitChainEpoch, remoteEpochsLen) + for i := range historical.Remote { + historical.Remote[i], err = decodeCommitChainEpoch(r) + if err != nil { + return CommitChainEpochHistory{}, err + } + } + } + + return CommitChainEpochHistory{ + normalizedCurrent: normalizedCurrent, + historical: historical, + }, nil +} + +// DCommitChainEpochHistory defines a tlv decoder for CommitChainEpochHistory. +func DCommitChainEpochHistory(r io.Reader, val interface{}, + buf *[8]byte, l uint64) error { + + if hist, ok := val.(*CommitChainEpochHistory); ok { + decoded, err := decodeCommitChainEpochHistory(r) + if err != nil { + return err + } + + *hist = decoded + + return nil + } + + return tlv.NewTypeForDecodingErr(val, "*CommitChainEpochHistory", l, l) +} + +// BeginChainEpochHistory initializes a new CommitChainEpochHistory with the +// original CommitmentParams specified in each party's ChannelConfig. +// +// NOTE: This function is only intended to be used during the funding workflow. +func BeginChainEpochHistory( + origCfgParams lntypes.Dual[CommitmentParams]) CommitChainEpochHistory { + + return CommitChainEpochHistory{ + normalizedCurrent: origCfgParams, + historical: lntypes.Dual[[]CommitChainEpoch]{}, + } +} + +// Record returns a TLV record that can be used to encode/decode a +// CommitChainEpochHistory to/from a TLV stream. +// +// NOTE: This is a part of the RecordProducer interface. +func (c *CommitChainEpochHistory) Record() tlv.Record { + return tlv.MakeDynamicRecord( + 0, c, c.Size, ECommitChainEpochHistory, + DCommitChainEpochHistory, + ) +} + +// Push allows a ChannelParty to change the CommitmentParams for the channel and +// mark the last commit heights for each party that the old CommitmentParams +// applied to. To use this function correctly you must call it with the +// understanding that the party making changes to its ChannelConfig will pass +// in the CommitmentParams from that config change unaltered. Finally the +// current commitment heights of both commit chains are passed in to mark the +// last height for each chain that the current channel epoch applies to. +func (c *CommitChainEpochHistory) Push(whoSpecified lntypes.ChannelParty, + params CommitmentParams, currentHeights lntypes.Dual[uint64]) { + + // Here we define a function that marks a set of normalized commitment + // parameters with the current commit height when the epoch concluded + // to create the CommitChainEpoch structure. + closeEpoch := func(normalizedCurrent CommitmentParams, + currentHeight uint64) CommitChainEpoch { + + return CommitChainEpoch{ + LastHeight: currentHeight, + normalizedParams: normalizedCurrent, + } + } + + // Using the function we just defined we now apply it to both the local + // and remote components of the current epoch which will define the last + // height that this set of normalized commitment parameters held for. + closed := lntypes.ZipWithDual( + c.normalizedCurrent, currentHeights, closeEpoch, + ) + + // Since go is unprincipled, we can't treat append as an actual function + // so we make a wrapper for our use case. + push := func(as []CommitChainEpoch, + a CommitChainEpoch) []CommitChainEpoch { + + return append(as, a) + } + + // We now take the closed epoch we just created and add it to the end of + // our history of channel epochs. + c.historical = lntypes.ZipWithDual( + c.historical, closed, push, + ) + + // Now we begin the task of assembling the new normalized current + // commitment parameters for both parties. + newCurrent := lntypes.Dual[CommitmentParams]{} + + // The party issuing the commitment parameter change is referred to as + // "main" here. It could be either the local or remote party but the + // point is that the new Csv for the main party will always be the same + // as the Csv from the last epoch, since a change to the Csv at the + // config level is an imposition on the other party's commitment + // transaction. However, the dust limit will be the dust limit set in + // the argument. + mainCsv := closed.GetForParty(whoSpecified).normalizedParams.CsvDelay + mainParams := CommitmentParams{ + DustLimit: params.DustLimit, + CsvDelay: mainCsv, + } + newCurrent.SetForParty(whoSpecified, mainParams) + + // The other party is referred to as counter here and the key here is + // that for the counterparty, their dust limit will remain the same as + // it was before, while their Csv will update since it is imposed by the + // main party. + counterParty := whoSpecified.CounterParty() + counterDustLimit := closed.GetForParty(counterParty). + normalizedParams.DustLimit + + counterParams := CommitmentParams{ + DustLimit: counterDustLimit, + CsvDelay: params.CsvDelay, + } + newCurrent.SetForParty(counterParty, counterParams) + + // Now that we have set the values appropriately for the newCurrent + // we set the normalizedCurrent values to be the newly computed current + // commitment values. + c.normalizedCurrent = newCurrent +} + +// NormalizedParamsAt queries the CommitChainEpochHistory for the normalized +// commitment parameters for the ChannelParty's commitment transaction at a +// given height. The parameters are referred to as "normalized" because they +// indicate the parameters that apply to that party's commitment transaction +// irrespective of which party is responsible for setting those parameters. +func (c *CommitChainEpochHistory) NormalizedParamsAt( + whoseCommit lntypes.ChannelParty, + height uint64) CommitmentParams { + + // Try to find the epoch that applies to the height. + histEpoch := search(c.historical.GetForParty(whoseCommit), height) + + // Extract just the portion of the epoch that specifies the parameters. + histParams := fn.MapOption(func(e CommitChainEpoch) CommitmentParams { + return e.normalizedParams + })(histEpoch) + + // If we didn't find it, then we use the current parameters. + curr := c.normalizedCurrent.GetForParty(whoseCommit) + + return histParams.UnwrapOr(curr) +} + +// search is responsible for finding the epoch that encloses the specified +// height. This means that the LastHeight of that epoch must be greater than +// or equal to the query height AND the previous epoch's LastHeight must be +// less than the query height. +func search(epochs []CommitChainEpoch, h uint64) fn.Option[CommitChainEpoch] { + // We implement a simple binary search here. + half := len(epochs) / 2 + + switch { + // We have a couple of edge cases here. If we somehow end up with an + // empty epoch history we are querying we return None. + case len(epochs) == 0: + return fn.None[CommitChainEpoch]() + + // If we have a single epoch in the history then that epoch is the + // correct one iff its LastHeight is greater than or equal to the + // query height. + case len(epochs) == 1: + if h <= epochs[0].LastHeight { + return fn.Some(epochs[0]) + } else { + return fn.None[CommitChainEpoch]() + } + + // Otherwise we begin our dividing of the slice. If our height falls + // between the LastHeight of the last epoch in the former half of the + // history and the LastHeight of the first epoch in the latter half of + // the history, then the first epoch of the latter half is the correct + // epoch. + case epochs[half-1].LastHeight < h && + h <= epochs[half].LastHeight: + + return fn.Some(epochs[half]) + + // Now that we've excluded the between case, our query height is in + // either half. If it's less than the LastHeight of the last epoch in + // the former half, then we will compute the search again on that half. + case h <= epochs[half-1].LastHeight: + return search(epochs[:half], h) + + // Otherwise it's in the latter half and so we will compute the search + // on that half. + case h > epochs[half].LastHeight: + return search(epochs[half:], h) + + // We should have excausted all cases, so this indicates something + // severely wrong with the algorithm and we choose to hard-eject. + default: + panic("non-exhaustive cases in commit epochs search") + } +} diff --git a/lntypes/channel_party.go b/lntypes/channel_party.go index 82cbd1045e7..ff9611855b5 100644 --- a/lntypes/channel_party.go +++ b/lntypes/channel_party.go @@ -109,6 +109,21 @@ func (d *Dual[A]) ModifyForParty(p ChannelParty, f func(A) A) A { } } +// RefForParty allows us to get a direct pointer access to the field that is +// associated with the given ChannelParty. +func (d *Dual[A]) RefForParty(p ChannelParty) *A { + switch p { + case Local: + return &d.Local + case Remote: + return &d.Remote + default: + panic(fmt.Sprintf( + "switch default triggered in ForParty: %v", p, + )) + } +} + // MapDual applies the function argument to both the Local and Remote fields of // the Dual[A] and returns a Dual[B] with that function applied. func MapDual[A, B any](d Dual[A], f func(A) B) Dual[B] { @@ -118,4 +133,13 @@ func MapDual[A, B any](d Dual[A], f func(A) B) Dual[B] { } } +// ZipWithDual allows us to combine two Duals into a single Dual using the +// provided function. +func ZipWithDual[A, B, C any](a Dual[A], b Dual[B], f func(A, B) C) Dual[C] { + return Dual[C]{ + Local: f(a.Local, b.Local), + Remote: f(a.Remote, b.Remote), + } +} + var BothParties []ChannelParty = []ChannelParty{Local, Remote} From d16810ae9d136e6707761fe1ea95a9fb3d7c9d6c Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Wed, 4 Sep 2024 14:09:24 -0700 Subject: [PATCH 14/15] channeldb+lnwallet: add epoch history to OpenChannel This commit takes the CommitChainEpochHistory defined in the last commit and adds it to the OpenChannel structure. As of this commit it is essentially redundant with the ChanCfgs but it will capture the history of the ChanCfgs when we add the ability to update them. --- channeldb/channel.go | 45 +++++++++++++++++++++++++++++++++++++++ channeldb/channel_test.go | 6 ++++++ lnwallet/channel.go | 1 + lnwallet/test_utils.go | 12 +++++++++++ lnwallet/wallet.go | 20 +++++++++++++++++ 5 files changed, 84 insertions(+) diff --git a/channeldb/channel.go b/channeldb/channel.go index b85a8a52ac9..f8dc623b0f0 100644 --- a/channeldb/channel.go +++ b/channeldb/channel.go @@ -260,6 +260,10 @@ type openChannelTlvData struct { // customBlob is an optional TLV encoded blob of data representing // custom channel funding information. customBlob tlv.OptionalRecordT[tlv.TlvType7, tlv.Blob] + + // commitChainEpochHistory is the optional TLV encoded blob of data + // representing the commit chain epoch history for the channel. + commitChainEpochHistory tlv.OptionalRecordT[tlv.TlvType8, CommitChainEpochHistory] //nolint:lll } // encode serializes the openChannelTlvData to the given io.Writer. @@ -281,6 +285,11 @@ func (c *openChannelTlvData) encode(w io.Writer) error { c.customBlob.WhenSome(func(blob tlv.RecordT[tlv.TlvType7, tlv.Blob]) { tlvRecords = append(tlvRecords, blob.Record()) }) + c.commitChainEpochHistory.WhenSome( + func(hist tlv.RecordT[tlv.TlvType8, CommitChainEpochHistory]) { + tlvRecords = append(tlvRecords, hist.Record()) + }, + ) // Create the tlv stream. tlvStream, err := tlv.NewStream(tlvRecords...) @@ -296,6 +305,7 @@ func (c *openChannelTlvData) decode(r io.Reader) error { memo := c.memo.Zero() tapscriptRoot := c.tapscriptRoot.Zero() blob := c.customBlob.Zero() + commitChainEpochHistory := c.commitChainEpochHistory.Zero() // Create the tlv stream. tlvStream, err := tlv.NewStream( @@ -306,6 +316,7 @@ func (c *openChannelTlvData) decode(r io.Reader) error { memo.Record(), tapscriptRoot.Record(), blob.Record(), + commitChainEpochHistory.Record(), ) if err != nil { return err @@ -325,6 +336,10 @@ func (c *openChannelTlvData) decode(r io.Reader) error { if _, ok := tlvs[c.customBlob.TlvType()]; ok { c.customBlob = tlv.SomeRecordT(blob) } + if _, ok := tlvs[c.commitChainEpochHistory.TlvType()]; ok { + c.commitChainEpochHistory = + tlv.SomeRecordT(commitChainEpochHistory) + } return nil } @@ -947,6 +962,10 @@ type OpenChannel struct { // commitment. Commitments lntypes.Dual[ChannelCommitment] + // CommitChainEpochHistory is the history of the CommitmentParams for + // each side of the channel. + CommitChainEpochHistory CommitChainEpochHistory + // RemoteCurrentRevocation is the current revocation for their // commitment transaction. However, since this the derived public key, // we don't yet have the private key so we aren't yet able to verify @@ -1207,6 +1226,11 @@ func (c *OpenChannel) amendTlvData(auxData openChannelTlvData) { auxData.customBlob.WhenSomeV(func(blob tlv.Blob) { c.CustomBlob = fn.Some(blob) }) + auxData.commitChainEpochHistory.WhenSomeV( + func(history CommitChainEpochHistory) { + c.CommitChainEpochHistory = history + }, + ) } // extractTlvData creates a new openChannelTlvData from the given channel. @@ -1224,6 +1248,11 @@ func (c *OpenChannel) extractTlvData() openChannelTlvData { realScid: tlv.NewRecordT[tlv.TlvType4]( c.confirmedScid, ), + commitChainEpochHistory: tlv.SomeRecordT( + tlv.NewRecordT[tlv.TlvType8]( + c.CommitChainEpochHistory, + ), + ), } if len(c.Memo) != 0 { @@ -4508,6 +4537,22 @@ func fetchChanInfo(chanBucket kvdb.RBucket, channel *OpenChannel) error { // open channel. channel.amendTlvData(auxData) + // Now that we've extracted the aux data, we can initialize the + // CommitChainEpochHistory. If we don't find it in the aux data, + // then we initialize it with the original CommitmentParams from + // the ChannelConfig. + histVal := auxData.commitChainEpochHistory.ValOpt() + channel.CommitChainEpochHistory = histVal.UnwrapOr( + BeginChainEpochHistory( + lntypes.MapDual( + channel.ChanCfgs, + func(cfg ChannelConfig) CommitmentParams { + return cfg.CommitmentParams + }, + ), + ), + ) + channel.Packager = NewChannelPackager(channel.ShortChannelID) // Finally, read the optional shutdown scripts. diff --git a/channeldb/channel_test.go b/channeldb/channel_test.go index af17297902e..a5167e1ee46 100644 --- a/channeldb/channel_test.go +++ b/channeldb/channel_test.go @@ -343,6 +343,12 @@ func createTestChannelState(t *testing.T, cdb *ChannelStateDB) *OpenChannel { Local: localCfg, Remote: remoteCfg, }, + CommitChainEpochHistory: BeginChainEpochHistory( + lntypes.Dual[CommitmentParams]{ + Local: localRenderingParams, + Remote: remoteRenderingParams, + }, + ), TotalMSatSent: 8, TotalMSatReceived: 2, Commitments: lntypes.Dual[ChannelCommitment]{ diff --git a/lnwallet/channel.go b/lnwallet/channel.go index c45acb47c08..dd0301558c6 100644 --- a/lnwallet/channel.go +++ b/lnwallet/channel.go @@ -7967,6 +7967,7 @@ func (lc *LightningChannel) ForceClose(opts ...ForceCloseOpt) ( return summary, nil } + // NewLocalForceCloseSummary generates a LocalForceCloseSummary from the given // channel state. The passed commitTx must be a fully signed commitment // transaction corresponding to localCommit. diff --git a/lnwallet/test_utils.go b/lnwallet/test_utils.go index 1bca0be912a..2a9a5e82a80 100644 --- a/lnwallet/test_utils.go +++ b/lnwallet/test_utils.go @@ -326,6 +326,12 @@ func CreateTestChannels(t *testing.T, chanType channeldb.ChannelType, Local: aliceCfg, Remote: bobCfg, }, + CommitChainEpochHistory: channeldb.BeginChainEpochHistory( + lntypes.Dual[channeldb.CommitmentParams]{ + Local: aliceCfg.CommitmentParams, + Remote: bobCfg.CommitmentParams, + }, + ), IdentityPub: aliceKeys[0].PubKey(), FundingOutpoint: *prevOut, ShortChannelID: shortChanID, @@ -348,6 +354,12 @@ func CreateTestChannels(t *testing.T, chanType channeldb.ChannelType, Local: bobCfg, Remote: aliceCfg, }, + CommitChainEpochHistory: channeldb.BeginChainEpochHistory( + lntypes.Dual[channeldb.CommitmentParams]{ + Local: bobCfg.CommitmentParams, + Remote: aliceCfg.CommitmentParams, + }, + ), IdentityPub: bobKeys[0].PubKey(), FundingOutpoint: *prevOut, ShortChannelID: shortChanID, diff --git a/lnwallet/wallet.go b/lnwallet/wallet.go index 898e11adfff..c9d9a527e18 100644 --- a/lnwallet/wallet.go +++ b/lnwallet/wallet.go @@ -2321,6 +2321,16 @@ func (l *LightningWallet) handleFundingCounterPartySigs(msg *addCounterPartySigs // he stored within the database. res.partialState.ChanCfgs.Local = res.ourContribution.toChanConfig() res.partialState.ChanCfgs.Remote = res.theirContribution.toChanConfig() + res.partialState.CommitChainEpochHistory = + channeldb.BeginChainEpochHistory( + lntypes.MapDual( + res.partialState.ChanCfgs, + //nolint:lll + func(cfg channeldb.ChannelConfig) channeldb.CommitmentParams { + return cfg.CommitmentParams + }, + ), + ) // We'll also record the finalized funding txn, which will allow us to // rebroadcast on startup in case we fail. @@ -2532,6 +2542,16 @@ func (l *LightningWallet) handleSingleFunderSigs(req *addSingleFunderSigsMsg) { pendingReservation.ourContribution.toChanConfig() chanState.ChanCfgs.Remote = pendingReservation.theirContribution.toChanConfig() + chanState.CommitChainEpochHistory = + channeldb.BeginChainEpochHistory( + lntypes.MapDual( + chanState.ChanCfgs, + //nolint:lll + func(cfg channeldb.ChannelConfig) channeldb.CommitmentParams { + return cfg.CommitmentParams + }, + ), + ) chanState.RevocationKeyLocator = pendingReservation.nextRevocationKeyLoc From ed1549454a7fd6b3998a3f92ba33764daf28f3d6 Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Wed, 4 Sep 2024 16:16:53 -0700 Subject: [PATCH 15/15] lnwallet: use CommitChainEpochHistory to determine CsvDelay during Breach This commit changes the way we create breach retributions to use the CsvDelay we compute from the CommitChainEpochHistory so as to account for the possibility that the channel parameters have changed since opening. --- lnwallet/channel.go | 31 ++++++++++++++++++++----------- lnwallet/channel_test.go | 6 +++--- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/lnwallet/channel.go b/lnwallet/channel.go index dd0301558c6..4c841d72a2d 100644 --- a/lnwallet/channel.go +++ b/lnwallet/channel.go @@ -2108,7 +2108,12 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64, return l.LocalAuxLeaf }, )(auxResult.AuxLeaves) - theirDelay := uint32(chanState.ChanCfgs.Remote.CsvDelay) + theirDelay := uint32( + chanState.CommitChainEpochHistory.NormalizedParamsAt( + lntypes.Remote, stateNum, + ).CsvDelay, + ) + theirScript, err := CommitScriptToSelf( chanState.ChanType, isRemoteInitiator, keyRing.ToLocalKey, keyRing.RevocationKey, theirDelay, leaseExpiry, localAuxLeaf, @@ -2128,7 +2133,7 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64, // we need. if revokedLog != nil { br, ourAmt, theirAmt, err = createBreachRetribution( - revokedLog, spendTx, chanState, keyRing, + revokedLog, spendTx, chanState, stateNum, keyRing, commitmentSecret, leaseExpiry, auxResult.AuxLeaves, ) if err != nil { @@ -2143,8 +2148,8 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64, // data can still function. This branch can be deleted once we // are confident that no legacy format is in use. br, ourAmt, theirAmt, err = createBreachRetributionLegacy( - revokedLogLegacy, chanState, keyRing, commitmentSecret, - ourScript, theirScript, leaseExpiry, + revokedLogLegacy, chanState, stateNum, keyRing, + commitmentSecret, ourScript, theirScript, leaseExpiry, ) if err != nil { return nil, err @@ -2325,7 +2330,7 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64, // createHtlcRetribution is a helper function to construct an HtlcRetribution // based on the passed params. -func createHtlcRetribution(chanState *channeldb.OpenChannel, +func createHtlcRetribution(chanState *channeldb.OpenChannel, stateNum uint64, keyRing *CommitmentKeyRing, commitHash chainhash.Hash, commitmentSecret *btcec.PrivateKey, leaseExpiry uint32, htlc *channeldb.HTLCEntry, @@ -2333,7 +2338,11 @@ func createHtlcRetribution(chanState *channeldb.OpenChannel, var emptyRetribution HtlcRetribution - theirDelay := uint32(chanState.ChanCfgs.Remote.CsvDelay) + theirDelay := uint32( + chanState.CommitChainEpochHistory.NormalizedParamsAt( + lntypes.Remote, stateNum, + ).CsvDelay, + ) isRemoteInitiator := !chanState.IsInitiator // We'll generate the original second level witness script now, as @@ -2446,7 +2455,7 @@ func createHtlcRetribution(chanState *channeldb.OpenChannel, // see if these fields are present there. If they are not, then // ErrRevLogDataMissing is returned. func createBreachRetribution(revokedLog *channeldb.RevocationLog, - spendTx *wire.MsgTx, chanState *channeldb.OpenChannel, + spendTx *wire.MsgTx, chanState *channeldb.OpenChannel, stateNum uint64, keyRing *CommitmentKeyRing, commitmentSecret *btcec.PrivateKey, leaseExpiry uint32, auxLeaves fn.Option[CommitAuxLeaves]) (*BreachRetribution, int64, int64, @@ -2458,7 +2467,7 @@ func createBreachRetribution(revokedLog *channeldb.RevocationLog, htlcRetributions := make([]HtlcRetribution, len(revokedLog.HTLCEntries)) for i, htlc := range revokedLog.HTLCEntries { hr, err := createHtlcRetribution( - chanState, keyRing, commitHash.Val, + chanState, stateNum, keyRing, commitHash.Val, commitmentSecret, leaseExpiry, htlc, auxLeaves, ) if err != nil { @@ -2562,8 +2571,8 @@ func createBreachRetribution(revokedLog *channeldb.RevocationLog, // BreachRetribution using a ChannelCommitment. Returns the constructed // retribution, our amount, their amount, and a possible non-nil error. func createBreachRetributionLegacy(revokedLog *channeldb.ChannelCommitment, - chanState *channeldb.OpenChannel, keyRing *CommitmentKeyRing, - commitmentSecret *btcec.PrivateKey, + chanState *channeldb.OpenChannel, stateNum uint64, + keyRing *CommitmentKeyRing, commitmentSecret *btcec.PrivateKey, ourScript, theirScript input.ScriptDescriptor, leaseExpiry uint32) (*BreachRetribution, int64, int64, error) { @@ -2609,7 +2618,7 @@ func createBreachRetributionLegacy(revokedLog *channeldb.ChannelCommitment, } hr, err := createHtlcRetribution( - chanState, keyRing, commitHash, + chanState, stateNum, keyRing, commitHash, commitmentSecret, leaseExpiry, entry, fn.None[CommitAuxLeaves](), ) diff --git a/lnwallet/channel_test.go b/lnwallet/channel_test.go index c5ae9a40a6a..d364e2cf6ea 100644 --- a/lnwallet/channel_test.go +++ b/lnwallet/channel_test.go @@ -9752,7 +9752,7 @@ func TestCreateHtlcRetribution(t *testing.T) { // Create the htlc retribution. hr, err := createHtlcRetribution( - aliceChannel.channelState, keyRing, commitHash, + aliceChannel.channelState, 0,keyRing, commitHash, dummyPrivate, leaseExpiry, htlc, fn.None[CommitAuxLeaves](), ) // Expect no error. @@ -9957,7 +9957,7 @@ func TestCreateBreachRetribution(t *testing.T) { br, our, their, err := createBreachRetribution( tc.revocationLog, tx, - aliceChannel.channelState, keyRing, + aliceChannel.channelState, 0, keyRing, dummyPrivate, leaseExpiry, fn.None[CommitAuxLeaves](), ) @@ -10016,7 +10016,7 @@ func TestCreateBreachRetributionLegacy(t *testing.T) { // Create the breach retribution using the legacy format. br, ourAmt, theirAmt, err := createBreachRetributionLegacy( - &revokedLog, aliceChannel.channelState, keyRing, + &revokedLog, aliceChannel.channelState, 0, keyRing, dummyPrivate, ourScript, theirScript, leaseExpiry, ) require.NoError(t, err)