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.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..4730220915d 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,15 @@ func genRandomOpenChannelShell() (*channeldb.OpenChannel, error) { ), ThawHeight: rand.Uint32(), IdentityPub: pub, - LocalChanCfg: localCfg, - RemoteChanCfg: remoteCfg, - LocalCommitment: localCommit, + Commitments: lntypes.Dual[channeldb.ChannelCommitment]{ + Local: 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..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 } @@ -938,23 +953,18 @@ type OpenChannel struct { // opening. InitialRemoteBalance lnwire.MilliSatoshi - // LocalChanCfg is the channel configuration for the local node. - LocalChanCfg ChannelConfig + // ChanCfgs is the channel configuration for the local and remote nodes. + ChanCfgs lntypes.Dual[ChannelConfig] - // RemoteChanCfg is the channel configuration for the remote node. - RemoteChanCfg ChannelConfig + // 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] - // 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 + // 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, @@ -1051,13 +1061,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, @@ -1216,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. @@ -1233,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 { @@ -1763,13 +1783,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 @@ -1823,7 +1843,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 { @@ -2413,7 +2433,7 @@ func (c *OpenChannel) UpdateCommitment(newCommitment *ChannelCommitment, return nil, err } - c.LocalCommitment = *newCommitment + c.Commitments.Local = *newCommitment return finalHtlcs, nil } @@ -2474,7 +2494,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) @@ -2486,7 +2506,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) @@ -3330,7 +3350,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 { @@ -3412,7 +3432,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 } @@ -3467,7 +3487,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 @@ -3562,7 +3582,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 } @@ -3984,7 +4004,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, @@ -4021,7 +4041,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, @@ -4033,10 +4055,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.LocalCommitment, &c.RemoteCommitment, nil + return fn.Ok(&c.Commitments) } // RemoteRevocationStore returns the most up to date commitment version of the @@ -4112,7 +4134,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 +4324,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 } @@ -4415,14 +4437,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, ) } @@ -4484,10 +4506,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 } @@ -4515,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. @@ -4593,11 +4631,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_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/channeldb/channel_test.go b/channeldb/channel_test.go index e92692201d8..a5167e1ee46 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,37 +331,47 @@ 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), - LocalChanCfg: localCfg, - RemoteChanCfg: remoteCfg, + 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, + }, + CommitChainEpochHistory: BeginChainEpochHistory( + lntypes.Dual[CommitmentParams]{ + Local: localRenderingParams, + Remote: remoteRenderingParams, + }, + ), 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(), @@ -659,7 +669,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, @@ -712,11 +722,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") @@ -788,7 +796,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 @@ -840,7 +848,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. @@ -1017,15 +1025,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.LocalChanCfg, + 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 92e0498eceb..2b7b0669ab8 100644 --- a/channeldb/db.go +++ b/channeldb/db.go @@ -1420,17 +1420,18 @@ 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, - 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..a606641622f 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, @@ -2344,15 +2347,19 @@ 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{ - LocalChanCfg: bobCfg, - RemoteChanCfg: aliceCfg, + ChanCfgs: lntypes.Dual[channeldb.ChannelConfig]{ + Local: bobCfg, + Remote: aliceCfg, + }, IdentityPub: bobKeyPub, FundingOutpoint: *prevOut, ShortChannelID: shortChanID, @@ -2362,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 808f41f2eee..3bcf636e245 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( @@ -435,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() @@ -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 { @@ -552,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) @@ -560,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 "+ @@ -580,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, }, } @@ -611,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 } @@ -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..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, @@ -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 @@ -479,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/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..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, @@ -2552,7 +2553,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 @@ -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, @@ -2917,7 +2918,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 +3018,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 +3511,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 +3522,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 +3550,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 +3744,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,8 +3865,8 @@ 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.LocalCommitment.CommitHeight+1, + channel.ChanCfgs.Local.MultiSigKey.PubKey, + channel.Commitments.Local.CommitHeight+1, musig2ShaChain, ) if err != nil { @@ -4257,7 +4258,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 +4268,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..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{ @@ -2946,8 +2947,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) @@ -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 cdb4f1f4ea4..7e54269cd49 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, @@ -315,17 +317,21 @@ 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{ - LocalChanCfg: bobCfg, - RemoteChanCfg: aliceCfg, + ChanCfgs: lntypes.Dual[channeldb.ChannelConfig]{ + Local: bobCfg, + Remote: aliceCfg, + }, IdentityPub: bobKeyPub, FundingOutpoint: *prevOut, ChanType: channeldb.SingleFunderTweaklessBit, @@ -334,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/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} 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..4c841d72a2d 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 @@ -909,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. @@ -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,12 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64, return l.LocalAuxLeaf }, )(auxResult.AuxLeaves) - theirDelay := uint32(chanState.RemoteChanCfg.CsvDelay) + theirDelay := uint32( + chanState.CommitChainEpochHistory.NormalizedParamsAt( + lntypes.Remote, stateNum, + ).CsvDelay, + ) + theirScript, err := CommitScriptToSelf( chanState.ChanType, isRemoteInitiator, keyRing.ToLocalKey, keyRing.RevocationKey, theirDelay, leaseExpiry, localAuxLeaf, @@ -2127,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 { @@ -2142,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 @@ -2156,7 +2162,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 +2174,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(), @@ -2213,7 +2219,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() @@ -2234,7 +2240,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 +2252,7 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64, } br.RemoteOutputSignDesc = &input.SignDescriptor{ - KeyDesc: chanState.LocalChanCfg. + KeyDesc: chanState.ChanCfgs.Local. RevocationBasePoint, DoubleTweak: commitmentSecret, WitnessScript: witnessScript, @@ -2293,7 +2299,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() @@ -2324,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, @@ -2332,7 +2338,11 @@ func createHtlcRetribution(chanState *channeldb.OpenChannel, var emptyRetribution HtlcRetribution - theirDelay := uint32(chanState.RemoteChanCfg.CsvDelay) + theirDelay := uint32( + chanState.CommitChainEpochHistory.NormalizedParamsAt( + lntypes.Remote, stateNum, + ).CsvDelay, + ) isRemoteInitiator := !chanState.IsInitiator // We'll generate the original second level witness script now, as @@ -2390,7 +2400,7 @@ func createHtlcRetribution(chanState *channeldb.OpenChannel, } signDesc := input.SignDescriptor{ - KeyDesc: chanState.LocalChanCfg. + KeyDesc: chanState.ChanCfgs.Local. RevocationBasePoint, DoubleTweak: commitmentSecret, WitnessScript: scriptInfo.WitnessScriptToSign(), @@ -2445,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, @@ -2457,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 { @@ -2561,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) { @@ -2596,7 +2606,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 @@ -2608,7 +2618,7 @@ func createBreachRetributionLegacy(revokedLog *channeldb.ChannelCommitment, } hr, err := createHtlcRetribution( - chanState, keyRing, commitHash, + chanState, stateNum, keyRing, commitHash, commitmentSecret, leaseExpiry, entry, fn.None[CommitAuxLeaves](), ) @@ -2752,10 +2762,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 +3138,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 +3767,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 +3850,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 +3859,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 +3969,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 +4583,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 +4732,7 @@ func genHtlcSigValidationJobs(chanState *channeldb.OpenChannel, var ( isLocalInitiator = chanState.IsInitiator - localChanCfg = chanState.LocalChanCfg + localChanCfg = chanState.ChanCfgs.Local chanType = chanState.ChanType ) @@ -5151,7 +5162,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 +5295,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 { @@ -5802,7 +5814,7 @@ func (lc *LightningChannel) ReceiveRevocation(revMsg *lnwire.RevokeAndAck) ( remoteChainTail, ) - remoteHTLCs := lc.channelState.RemoteCommitment.Htlcs + remoteHTLCs := lc.channelState.Commitments.Remote.Htlcs return fwdPkg, remoteHTLCs, nil } @@ -5922,12 +5934,12 @@ func (lc *LightningChannel) GetDustSum(whoseCommit lntypes.ChannelParty, var dustSum lnwire.MilliSatoshi - dustLimit := lc.channelState.LocalChanCfg.DustLimit - commit := lc.channelState.LocalCommitment + dustLimit := lc.channelState.ChanCfgs.Local.DustLimit + commit := lc.channelState.Commitments.Local if whoseCommit.IsRemote() { // Calculate dust sum on the remote's commitment. - dustLimit = lc.channelState.RemoteChanCfg.DustLimit - commit = lc.channelState.RemoteCommitment + dustLimit = lc.channelState.ChanCfgs.Remote.DustLimit + commit = lc.channelState.Commitments.Remote } chanType := lc.channelState.ChanType @@ -5997,8 +6009,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: @@ -6615,13 +6627,13 @@ 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, 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 +6735,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 +6765,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 +6807,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. @@ -6849,7 +6861,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, @@ -6858,7 +6870,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, @@ -6886,7 +6898,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. @@ -7125,7 +7137,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, @@ -7135,7 +7147,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), } @@ -7336,7 +7348,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, @@ -7348,7 +7360,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{ @@ -7471,7 +7483,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, @@ -7482,7 +7494,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(), @@ -7676,7 +7688,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, @@ -7686,7 +7698,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, @@ -7949,7 +7961,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, @@ -7978,7 +7990,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,14 +8002,14 @@ 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( leafStore, func(s AuxLeafStore) fn.Result[CommitDiffAuxResult] { return s.FetchLeavesFromCommit( NewAuxChanState(chanState), - chanState.LocalCommitment, *keyRing, + chanState.Commitments.Local, *keyRing, lntypes.Local, ) }, @@ -8066,7 +8078,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{ @@ -8109,7 +8121,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, @@ -8118,7 +8130,7 @@ func NewLocalForceCloseSummary(chanState *channeldb.OpenChannel, SignDesc: commitResolution.SelfOutputSignDesc, KeyRing: keyRing, CsvDelay: csvTimeout, - CommitFee: chanState.LocalCommitment.CommitFee, + CommitFee: chanState.Commitments.Local.CommitFee, }) }, ) @@ -8134,11 +8146,11 @@ 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.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, ) @@ -8257,9 +8269,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 @@ -8286,9 +8298,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 @@ -8358,9 +8372,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 @@ -8390,9 +8404,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 +8456,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,10 +8526,11 @@ 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, + lc.channelState, lc.channelState.Commitments.Local.CommitTx, localKeyRing, lntypes.Local, ) if err != nil { @@ -8524,11 +8541,11 @@ 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, + lc.channelState, lc.channelState.Commitments.Remote.CommitTx, remoteKeyRing, lntypes.Remote, ) if err != nil { @@ -8545,8 +8562,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 +8596,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 +8634,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 +8664,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 +8786,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 +8839,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 +8850,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 +8863,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 +9092,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 { @@ -9299,7 +9318,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 @@ -9308,7 +9327,7 @@ func (lc *LightningChannel) LocalBalanceDust() (bool, btcutil.Amount) { localBalance += 2 * AnchorSize } - localDust := chanState.LocalChanCfg.DustLimit + localDust := chanState.ChanCfgs.Local.DustLimit return localBalance <= localDust, localDust } @@ -9321,7 +9340,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 @@ -9330,7 +9349,7 @@ func (lc *LightningChannel) RemoteBalanceDust() (bool, btcutil.Amount) { remoteBalance += 2 * AnchorSize } - remoteDust := chanState.RemoteChanCfg.DustLimit + remoteDust := chanState.ChanCfgs.Remote.DustLimit return remoteBalance <= remoteDust, remoteDust } @@ -9342,7 +9361,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() @@ -9363,7 +9382,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 @@ -9379,8 +9398,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. @@ -9521,7 +9540,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 @@ -9530,8 +9551,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) @@ -9623,7 +9644,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 +9661,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 +9714,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 +9748,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 +9805,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. @@ -9794,7 +9815,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 8fc3d8b4681..d364e2cf6ea 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. @@ -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, ) { @@ -1031,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) @@ -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, @@ -1134,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") } @@ -1197,7 +1199,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 +1231,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,16 +1244,17 @@ 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) } 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") } @@ -1291,15 +1295,15 @@ 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) - 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. @@ -1323,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") @@ -1339,7 +1342,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") } @@ -1347,20 +1350,22 @@ 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) } 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) } 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") } @@ -1378,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") } @@ -1398,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) @@ -1412,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), @@ -1432,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", @@ -1474,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) @@ -1503,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. @@ -1707,19 +1716,19 @@ 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. // 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, ), ) @@ -2126,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 @@ -2171,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) } } @@ -2213,17 +2224,17 @@ 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) { - 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() { @@ -2232,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[:] @@ -2306,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", @@ -2376,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. @@ -2501,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") } @@ -2510,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") } } @@ -2560,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") @@ -2572,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") @@ -2595,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") @@ -2607,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") @@ -2684,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") @@ -2697,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") @@ -2719,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") @@ -2731,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") @@ -2809,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") @@ -2833,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") @@ -2858,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") @@ -2870,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") @@ -2896,7 +2913,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 @@ -4731,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 @@ -4758,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 @@ -4874,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") @@ -4958,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 @@ -5062,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") @@ -5088,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") @@ -5230,10 +5247,10 @@ 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, + aliceChannel.channelState.Commitments.Local.FeePerKw, ) assertBandwidthEstimateCorrect := func(aliceInitiate bool, @@ -5366,17 +5383,17 @@ 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, + aliceChannel.channelState.Commitments.Local.FeePerKw, ) // When calculating the fee buffer sending an htlc we need to account @@ -5389,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), @@ -5553,14 +5570,14 @@ 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( - aliceChannel.channelState.LocalCommitment.FeePerKw, + aliceChannel.channelState.Commitments.Local.FeePerKw, ) htlcTimeoutFee := lnwire.NewMSatFromSatoshis( HtlcTimeoutFee(aliceChannel.channelState.ChanType, feeRate), @@ -5640,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. @@ -5662,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) @@ -6090,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{}), @@ -6236,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{}), @@ -6388,14 +6406,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 +6523,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 +6623,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. @@ -6637,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) @@ -6648,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) @@ -6684,20 +6706,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 } @@ -6724,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, @@ -6801,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, @@ -6817,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, @@ -6836,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, @@ -6862,11 +6888,11 @@ 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.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 @@ -6910,18 +6936,18 @@ 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.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 +6976,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 +7016,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 +7055,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. @@ -7066,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. @@ -7086,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{}), @@ -7970,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 @@ -9362,7 +9389,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 +9710,12 @@ func testGetDustSum(t *testing.T, chantype channeldb.ChannelType) { func deriveDummyRetributionParams(chanState *channeldb.OpenChannel) (uint32, *CommitmentKeyRing, chainhash.Hash) { - config := chanState.RemoteChanCfg - commitHash := chanState.RemoteCommitment.CommitTx.TxHash() + config := chanState.ChanCfgs.Remote + commitHash := chanState.Commitments.Remote.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 @@ -9725,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. @@ -9930,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](), ) @@ -9974,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] @@ -9989,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) @@ -10044,8 +10071,8 @@ func testNewBreachRetribution(t *testing.T, chanType channeldb.ChannelType) { breachHeight := uint32(101) stateNum := uint64(0) chainHash := aliceChannel.channelState.ChainHash - theirDelay := uint32(aliceChannel.channelState.RemoteChanCfg.CsvDelay) - breachTx := aliceChannel.channelState.RemoteCommitment.CommitTx + theirDelay := uint32(aliceChannel.channelState.ChanCfgs.Remote.CsvDelay) + 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. @@ -10067,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) @@ -10405,13 +10432,13 @@ func TestAsynchronousSendingContraint(t *testing.T) { ) require.NoError(t, err) - aliceReserve := aliceChannel.channelState.LocalChanCfg.ChanReserve + aliceReserve := aliceChannel.channelState.ChanCfgs.Local.ChanReserve capacity := aliceChannel.channelState.Capacity // Static fee rate of 6000 sats/kw. feePerKw := chainfee.SatPerKWeight( - aliceChannel.channelState.LocalCommitment.FeePerKw, + aliceChannel.channelState.Commitments.Local.FeePerKw, ) additionalHtlc := feePerKw.FeeForWeight(input.HTLCWeight) @@ -10440,7 +10467,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,13 +10565,13 @@ func TestAsynchronousSendingWithFeeBuffer(t *testing.T) { ) require.NoError(t, err) - aliceReserve := aliceChannel.channelState.LocalChanCfg.ChanReserve + aliceReserve := aliceChannel.channelState.ChanCfgs.Local.ChanReserve capacity := aliceChannel.channelState.Capacity // 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 @@ -10572,7 +10599,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 +10683,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) @@ -10678,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)) } @@ -10729,13 +10757,13 @@ func TestEnforceFeeBuffer(t *testing.T) { ) require.NoError(t, err) - aliceReserve := aliceChannel.channelState.LocalChanCfg.ChanReserve + aliceReserve := aliceChannel.channelState.ChanCfgs.Local.ChanReserve capacity := aliceChannel.channelState.Capacity // 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). @@ -10813,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 36ff75edeb4..b8ff9719cf3 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, @@ -1277,20 +1279,20 @@ 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 // 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/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 2253232962a..2a9a5e82a80 100644 --- a/lnwallet/test_utils.go +++ b/lnwallet/test_utils.go @@ -322,8 +322,16 @@ func CreateTestChannels(t *testing.T, chanType channeldb.ChannelType, ) aliceChannelState := &channeldb.OpenChannel{ - LocalChanCfg: aliceCfg, - RemoteChanCfg: bobCfg, + ChanCfgs: lntypes.Dual[channeldb.ChannelConfig]{ + 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, @@ -333,15 +341,25 @@ 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{ - LocalChanCfg: bobCfg, - RemoteChanCfg: aliceCfg, + ChanCfgs: lntypes.Dual[channeldb.ChannelConfig]{ + 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, @@ -351,10 +369,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 7912772962b..024d74b1f9f 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, @@ -985,15 +987,19 @@ 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{ - LocalChanCfg: localCfg, - RemoteChanCfg: remoteCfg, + ChanCfgs: lntypes.Dual[channeldb.ChannelConfig]{ + Local: localCfg, + Remote: remoteCfg, + }, IdentityPub: localDummy2.PubKey(), FundingOutpoint: *prevOut, ShortChannelID: shortChanID, @@ -1003,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 a9018437d5c..c9d9a527e18 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() @@ -2318,8 +2319,18 @@ 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() + 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. @@ -2374,12 +2385,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 +2403,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 +2458,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 +2478,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 @@ -2525,8 +2538,20 @@ 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.CommitChainEpochHistory = + channeldb.BeginChainEpochHistory( + lntypes.MapDual( + chanState.ChanCfgs, + //nolint:lll + func(cfg channeldb.ChannelConfig) channeldb.CommitmentParams { + return cfg.CommitmentParams + }, + ), + ) chanState.RevocationKeyLocator = pendingReservation.nextRevocationKeyLoc @@ -2620,8 +2645,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/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 } diff --git a/lnwire/dyn_commit.go b/lnwire/dyn_commit.go new file mode 100644 index 00000000000..73b992f6175 --- /dev/null +++ b/lnwire/dyn_commit.go @@ -0,0 +1,135 @@ +package lnwire + +import ( + "bytes" + "io" + + "github.com/btcsuite/btcd/btcutil" + "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 extra ExtraOpaqueData + err := extra.PackRecords(dynProposeRecords(&dc.DynPropose)...) + if err != nil { + return err + } + dc.ExtraData = extra + + 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 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, + ) + if err != nil { + return err + } + + // Check the results of the TLV Stream decoding and appropriately set + // message fields. + 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 { + 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/dyn_propose.go b/lnwire/dyn_propose.go index b0cc1198e94..a38df36caef 100644 --- a/lnwire/dyn_propose.go +++ b/lnwire/dyn_propose.go @@ -4,47 +4,10 @@ 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" ) -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 = 1 - - // DPChannelReserveSatoshis is the TLV type number that identifies the - // for DynPropose.ChannelReserve. - DPChannelReserveSatoshis tlv.Type = 2 - - // DPToSelfDelay is the TLV type number that identifies the record for - // DynPropose.CsvDelay. - DPToSelfDelay tlv.Type = 3 - - // DPMaxAcceptedHtlcs is the TLV type number that identifies the record - // 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 - - // 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 // process. It is sent by both parties to propose new channel parameters. type DynPropose struct { @@ -52,44 +15,33 @@ 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] + 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 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] - - // FundingKey, if not nil, proposes a change to the funding_pubkey - // parameter of the sender. - FundingKey fn.Option[btcec.PublicKey] + MaxAcceptedHTLCs tlv.OptionalRecordT[tlv.TlvType10, uint16] // ChannelType, if not nil, proposes a change to the channel_type // 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] + 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 @@ -110,88 +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.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 err - } - - var extraBytesWriter bytes.Buffer - if err := tlvStream.Encode(&extraBytesWriter); err != nil { - return err - } - dp.ExtraData = ExtraOpaqueData(extraBytesWriter.Bytes()) - if err := WriteChannelID(w, dp.ChanID); err != nil { return err } - if err := WriteBool(w, dp.Initiator); err != nil { + producers := dynProposeRecords(dp) + + err := EncodeMessageExtraData(&dp.ExtraData, producers...) + if err != nil { return err } @@ -205,7 +83,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 } @@ -216,91 +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 dustLimit tlv.RecordT[tlv.TlvType0, uint64] + var maxValue tlv.RecordT[tlv.TlvType2, uint64] + var htlcMin tlv.RecordT[tlv.TlvType4, uint64] + var reserve tlv.RecordT[tlv.TlvType6, uint64] + csvDelay := dp.CsvDelay.Zero() + maxHtlcs := dp.MaxAcceptedHTLCs.Zero() + chanType := dp.ChannelType.Zero() + + typeMap, err := tlvRecords.ExtractRecords( + &dustLimit, &maxValue, &htlcMin, &reserve, &csvDelay, &maxHtlcs, + &chanType, ) - - var 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 { - 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[DPChannelReserveSatoshis]; ok && val == nil { - dp.ChannelReserve = fn.Some(btcutil.Amount(reserveScratch)) + 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[DPToSelfDelay]; ok && val == nil { - dp.CsvDelay = fn.Some(csvDelayScratch) + 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[DPMaxAcceptedHtlcs]; ok && val == nil { - dp.MaxAcceptedHTLCs = fn.Some(maxHtlcsScratch) + if val, ok := typeMap[dp.CsvDelay.TlvType()]; ok && val == nil { + dp.CsvDelay = tlv.SomeRecordT(csvDelay) } - if val, ok := typeMap[DPFundingPubkey]; ok && val == nil { - dp.FundingKey = fn.Some(*fundingKeyScratch) + 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[DPKickoffFeerate]; ok && val == nil { - dp.KickoffFeerate = fn.Some( - chainfee.SatPerKWeight(kickoffFeerateScratch), - ) + if val, ok := typeMap[dp.ChannelType.TlvType()]; ok && val == nil { + dp.ChannelType = tlv.SomeRecordT(chanType) } if len(tlvRecords) != 0 { @@ -317,3 +156,72 @@ 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) { + producers := dynProposeRecords(dp) + + var extra ExtraOpaqueData + err := extra.PackRecords(producers...) + 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 recordProducers +} 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..156c0576381 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" @@ -828,87 +827,91 @@ 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, _ := btcec.NewPrivateKey() - dp.FundingKey = fn.Some(*v.PubKey()) - } - - if rand.Uint32()%2 == 0 { - v := ChannelType(*NewRawFeatureVector()) - dp.ChannelType = fn.Some(v) - } - - if rand.Uint32()%2 == 0 { - v := chainfee.SatPerKWeight(rand.Uint32()) - dp.KickoffFeerate = 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(DPChannelReserveSatoshis), + FeatureBit(dp.HtlcMinimum.TlvType()), ) } if rand.Uint32()%2 == 0 { - features.Set(FeatureBit(DPToSelfDelay)) + features.Set( + FeatureBit(dp.ChannelReserve.TlvType()), + ) } if rand.Uint32()%2 == 0 { - features.Set(FeatureBit(DPMaxAcceptedHtlcs)) + features.Set(FeatureBit(dp.CsvDelay.TlvType())) } if rand.Uint32()%2 == 0 { - features.Set(FeatureBit(DPFundingPubkey)) + features.Set( + FeatureBit( + dp.MaxAcceptedHTLCs.TlvType(), + ), + ) } if rand.Uint32()%2 == 0 { - features.Set(FeatureBit(DPChannelType)) + features.Set( + FeatureBit(dp.ChannelType.TlvType()), + ) } - if rand.Uint32()%2 == 0 { - features.Set(FeatureBit(DPKickoffFeerate)) - } dr.UpdateRejections = *features v[0] = reflect.ValueOf(dr) @@ -925,6 +928,51 @@ 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 { + rec := dc.DustLimit.Zero() + rec.Val = btcutil.Amount(rand.Uint32()) + dc.DustLimit = tlv.SomeRecordT(rec) + } + + if rand.Uint32()%2 == 0 { + rec := dc.MaxValueInFlight.Zero() + rec.Val = MilliSatoshi(rand.Uint32()) + dc.MaxValueInFlight = tlv.SomeRecordT(rec) + } + + if rand.Uint32()%2 == 0 { + rec := dc.ChannelReserve.Zero() + rec.Val = btcutil.Amount(rand.Uint32()) + dc.ChannelReserve = tlv.SomeRecordT(rec) + } + + if rand.Uint32()%2 == 0 { + rec := dc.CsvDelay.Zero() + rec.Val = uint16(rand.Uint32()) + dc.CsvDelay = tlv.SomeRecordT(rec) + } + + if rand.Uint32()%2 == 0 { + rec := dc.MaxAcceptedHTLCs.Zero() + rec.Val = uint16(rand.Uint32()) + dc.MaxAcceptedHTLCs = tlv.SomeRecordT(rec) + } + + if rand.Uint32()%2 == 0 { + rec := dc.ChannelType.Zero() + rec.Val = ChannelType(*NewRawFeatureVector()) + dc.ChannelType = tlv.SomeRecordT(rec) + } + + v[0] = reflect.ValueOf(dc) + }, MsgKickoffSig: func(v []reflect.Value, r *rand.Rand) { ks := KickoffSig{ ExtraData: make([]byte, 0), @@ -1779,6 +1827,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: diff --git a/peer/test_utils.go b/peer/test_utils.go index 9034bb5a962..e75bffd792e 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, @@ -255,15 +257,19 @@ 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{ - LocalChanCfg: bobCfg, - RemoteChanCfg: aliceCfg, + ChanCfgs: lntypes.Dual[channeldb.ChannelConfig]{ + Local: bobCfg, + Remote: aliceCfg, + }, IdentityPub: bobKeyPub, FundingOutpoint: *prevOut, ChanType: channeldb.SingleFunderTweaklessBit, @@ -272,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/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..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,13 +3859,18 @@ 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()), - LocalChanReserveSat: int64(pendingChan.LocalChanCfg.ChanReserve), - RemoteChanReserveSat: int64(pendingChan.RemoteChanCfg.ChanReserve), + 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 + RemoteChanReserveSat: int64(pendingChan.ChanCfgs.Remote.ChanReserve), Initiator: rpcInitiator(pendingChan.IsInitiator), CommitmentType: rpcCommitmentType(pendingChan.ChanType), Private: isPrivate(pendingChan), @@ -3953,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) @@ -4086,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, ) } @@ -4148,13 +4155,17 @@ 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()), - LocalChanReserveSat: int64(waitingClose.LocalChanCfg.ChanReserve), - RemoteChanReserveSat: int64(waitingClose.RemoteChanCfg.ChanReserve), + 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 + RemoteChanReserveSat: int64(waitingClose.ChanCfgs.Remote.ChanReserve), Initiator: rpcInitiator(waitingClose.IsInitiator), CommitmentType: rpcCommitmentType(waitingClose.ChanType), NumForwardingPackages: int64(len(fwdPkgs)), @@ -4627,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 { @@ -4673,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 @@ -4736,10 +4748,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 +4760,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.