From e3a9d0acbec6f74939373a3c8bdf7ed517e8b253 Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Thu, 9 May 2024 14:32:45 -0700 Subject: [PATCH 1/2] multi: break ChannelConstraints into two sub-structures This commit breaks the ChannelConstraints structure into two sub-structures that reflect the fundamental differences in how these parameters are used. On its face it may not seem necessary, however the distinction introduced here is relevant for how we will be implementing the Dynamic Commitments proposal. --- chanbackup/single_test.go | 119 +++++++++-------- channeldb/channel.go | 42 +++--- channeldb/channel_test.go | 45 ++++--- channeldb/db_test.go | 8 +- contractcourt/breach_arbitrator_test.go | 16 ++- funding/manager.go | 170 +++++++++++++----------- htlcswitch/test_utils.go | 22 +-- lnwallet/reservation.go | 74 +++++++---- lnwallet/test/test_interface.go | 24 ++-- lnwallet/test_utils.go | 16 ++- lnwallet/transactions_test.go | 20 +-- lnwallet/wallet.go | 2 +- peer/test_utils.go | 16 ++- routing/localchans/manager.go | 2 +- routing/localchans/manager_test.go | 4 +- 15 files changed, 338 insertions(+), 242 deletions(-) diff --git a/chanbackup/single_test.go b/chanbackup/single_test.go index ab418e190..c1e940740 100644 --- a/chanbackup/single_test.go +++ b/chanbackup/single_test.go @@ -126,6 +126,64 @@ func genRandomOpenChannelShell() (*channeldb.OpenChannel, error) { chanType := channeldb.ChannelType(rand.Intn(8)) + localCfg := channeldb.ChannelConfig{ + ChannelStateBounds: channeldb.ChannelStateBounds{}, + CommitmentParams: channeldb.CommitmentParams{ + CsvDelay: uint16(rand.Int63()), + }, + MultiSigKey: keychain.KeyDescriptor{ + KeyLocator: keychain.KeyLocator{ + Family: keychain.KeyFamily(rand.Int63()), + Index: uint32(rand.Int63()), + }, + }, + RevocationBasePoint: keychain.KeyDescriptor{ + KeyLocator: keychain.KeyLocator{ + Family: keychain.KeyFamily(rand.Int63()), + Index: uint32(rand.Int63()), + }, + }, + PaymentBasePoint: keychain.KeyDescriptor{ + KeyLocator: keychain.KeyLocator{ + Family: keychain.KeyFamily(rand.Int63()), + Index: uint32(rand.Int63()), + }, + }, + DelayBasePoint: keychain.KeyDescriptor{ + KeyLocator: keychain.KeyLocator{ + Family: keychain.KeyFamily(rand.Int63()), + Index: uint32(rand.Int63()), + }, + }, + HtlcBasePoint: keychain.KeyDescriptor{ + KeyLocator: keychain.KeyLocator{ + Family: keychain.KeyFamily(rand.Int63()), + Index: uint32(rand.Int63()), + }, + }, + } + + remoteCfg := channeldb.ChannelConfig{ + CommitmentParams: channeldb.CommitmentParams{ + CsvDelay: uint16(rand.Int63()), + }, + MultiSigKey: keychain.KeyDescriptor{ + PubKey: pub, + }, + RevocationBasePoint: keychain.KeyDescriptor{ + PubKey: pub, + }, + PaymentBasePoint: keychain.KeyDescriptor{ + PubKey: pub, + }, + DelayBasePoint: keychain.KeyDescriptor{ + PubKey: pub, + }, + HtlcBasePoint: keychain.KeyDescriptor{ + PubKey: pub, + }, + } + return &channeldb.OpenChannel{ ChainHash: chainHash, ChanType: chanType, @@ -134,63 +192,10 @@ func genRandomOpenChannelShell() (*channeldb.OpenChannel, error) { ShortChannelID: lnwire.NewShortChanIDFromInt( uint64(rand.Int63()), ), - ThawHeight: rand.Uint32(), - IdentityPub: pub, - LocalChanCfg: channeldb.ChannelConfig{ - ChannelConstraints: channeldb.ChannelConstraints{ - CsvDelay: uint16(rand.Int63()), - }, - MultiSigKey: keychain.KeyDescriptor{ - KeyLocator: keychain.KeyLocator{ - Family: keychain.KeyFamily(rand.Int63()), - Index: uint32(rand.Int63()), - }, - }, - RevocationBasePoint: keychain.KeyDescriptor{ - KeyLocator: keychain.KeyLocator{ - Family: keychain.KeyFamily(rand.Int63()), - Index: uint32(rand.Int63()), - }, - }, - PaymentBasePoint: keychain.KeyDescriptor{ - KeyLocator: keychain.KeyLocator{ - Family: keychain.KeyFamily(rand.Int63()), - Index: uint32(rand.Int63()), - }, - }, - DelayBasePoint: keychain.KeyDescriptor{ - KeyLocator: keychain.KeyLocator{ - Family: keychain.KeyFamily(rand.Int63()), - Index: uint32(rand.Int63()), - }, - }, - HtlcBasePoint: keychain.KeyDescriptor{ - KeyLocator: keychain.KeyLocator{ - Family: keychain.KeyFamily(rand.Int63()), - Index: uint32(rand.Int63()), - }, - }, - }, - RemoteChanCfg: channeldb.ChannelConfig{ - ChannelConstraints: channeldb.ChannelConstraints{ - CsvDelay: uint16(rand.Int63()), - }, - MultiSigKey: keychain.KeyDescriptor{ - PubKey: pub, - }, - RevocationBasePoint: keychain.KeyDescriptor{ - PubKey: pub, - }, - PaymentBasePoint: keychain.KeyDescriptor{ - PubKey: pub, - }, - DelayBasePoint: keychain.KeyDescriptor{ - PubKey: pub, - }, - HtlcBasePoint: keychain.KeyDescriptor{ - PubKey: pub, - }, - }, + ThawHeight: rand.Uint32(), + IdentityPub: pub, + LocalChanCfg: localCfg, + RemoteChanCfg: remoteCfg, RevocationProducer: shaChainProducer, }, nil } diff --git a/channeldb/channel.go b/channeldb/channel.go index ad0208467..7569fc30e 100644 --- a/channeldb/channel.go +++ b/channeldb/channel.go @@ -395,19 +395,11 @@ func (c ChannelType) IsTaproot() bool { return c&SimpleTaprootFeatureBit == SimpleTaprootFeatureBit } -// ChannelConstraints represents a set of constraints meant to allow a node to -// limit their exposure, enact flow control and ensure that all HTLCs are -// economically relevant. This struct will be mirrored for both sides of the -// channel, as each side will enforce various constraints that MUST be adhered -// to for the life time of the channel. The parameters for each of these -// constraints are static for the duration of the channel, meaning the channel -// must be torn down for them to change. -type ChannelConstraints struct { - // DustLimit is the threshold (in satoshis) below which any outputs - // should be trimmed. When an output is trimmed, it isn't materialized - // as an actual output, but is instead burned to miner's fees. - DustLimit btcutil.Amount - +// ChannelStateBounds are the parameters from OpenChannel and AcceptChannel +// that are responsible for providing bounds on the state space of the abstract +// channel state. These values must be remembered for normal channel operation +// but they do not impact how we compute the commitment transactions themselves. +type ChannelStateBounds struct { // ChanReserve is an absolute reservation on the channel for the // owner of this set of constraints. This means that the current // settled balance for this node CANNOT dip below the reservation @@ -433,6 +425,19 @@ type ChannelConstraints struct { // acted upon in the case of a unilateral channel closure or a contract // breach. MaxAcceptedHtlcs uint16 +} + +// CommitmentParams are the parameters from OpenChannel and +// AcceptChannel that are required to render an abstract channel state to a +// concrete commitment transaction. These values are necessary to (re)compute +// the commitment transaction. We treat these differently than the state space +// bounds because their history needs to be stored in order to properly handle +// chain resolution. +type CommitmentParams struct { + // DustLimit is the threshold (in satoshis) below which any outputs + // should be trimmed. When an output is trimmed, it isn't materialized + // as an actual output, but is instead burned to miner's fees. + DustLimit btcutil.Amount // CsvDelay is the relative time lock delay expressed in blocks. Any // settled outputs that pay to the owner of this channel configuration @@ -448,12 +453,17 @@ type ChannelConstraints struct { // nature of HTLC's allotted, the keys to be used for delivery, and relative // time lock parameters. type ChannelConfig struct { - // ChannelConstraints is the set of constraints that must be upheld for - // the duration of the channel for the owner of this channel + // ChannelStateBounds is the set of constraints that must be + // upheld for the duration of the channel for the owner of this channel // configuration. Constraints govern a number of flow control related // parameters, also including the smallest HTLC that will be accepted // by a participant. - ChannelConstraints + ChannelStateBounds + + // CommitmentParams is an embedding of the parameters + // required to render an abstract channel state into a concrete + // commitment transaction. + CommitmentParams // MultiSigKey is the key to be used within the 2-of-2 output script // for the owner of this channel config. diff --git a/channeldb/channel_test.go b/channeldb/channel_test.go index e630b1c48..a7f3c1ebe 100644 --- a/channeldb/channel_test.go +++ b/channeldb/channel_test.go @@ -235,15 +235,21 @@ func createTestChannelState(t *testing.T, cdb *ChannelStateDB) *OpenChannel { } } + localStateBounds := ChannelStateBounds{ + MaxPendingAmount: lnwire.MilliSatoshi(rand.Int63()), + ChanReserve: btcutil.Amount(rand.Int63()), + MinHTLC: lnwire.MilliSatoshi(rand.Int63()), + MaxAcceptedHtlcs: uint16(rand.Int31()), + } + + localRenderingParams := CommitmentParams{ + DustLimit: btcutil.Amount(rand.Int63()), + CsvDelay: uint16(rand.Int31()), + } + localCfg := ChannelConfig{ - ChannelConstraints: ChannelConstraints{ - DustLimit: btcutil.Amount(rand.Int63()), - MaxPendingAmount: lnwire.MilliSatoshi(rand.Int63()), - ChanReserve: btcutil.Amount(rand.Int63()), - MinHTLC: lnwire.MilliSatoshi(rand.Int63()), - MaxAcceptedHtlcs: uint16(rand.Int31()), - CsvDelay: uint16(rand.Int31()), - }, + ChannelStateBounds: localStateBounds, + CommitmentParams: localRenderingParams, MultiSigKey: keychain.KeyDescriptor{ PubKey: privKey.PubKey(), }, @@ -260,15 +266,22 @@ func createTestChannelState(t *testing.T, cdb *ChannelStateDB) *OpenChannel { PubKey: privKey.PubKey(), }, } + + remoteStateBounds := ChannelStateBounds{ + MaxPendingAmount: lnwire.MilliSatoshi(rand.Int63()), + ChanReserve: btcutil.Amount(rand.Int63()), + MinHTLC: lnwire.MilliSatoshi(rand.Int63()), + MaxAcceptedHtlcs: uint16(rand.Int31()), + } + + remoteRenderingParams := CommitmentParams{ + DustLimit: btcutil.Amount(rand.Int63()), + CsvDelay: uint16(rand.Int31()), + } + remoteCfg := ChannelConfig{ - ChannelConstraints: ChannelConstraints{ - DustLimit: btcutil.Amount(rand.Int63()), - MaxPendingAmount: lnwire.MilliSatoshi(rand.Int63()), - ChanReserve: btcutil.Amount(rand.Int63()), - MinHTLC: lnwire.MilliSatoshi(rand.Int63()), - MaxAcceptedHtlcs: uint16(rand.Int31()), - CsvDelay: uint16(rand.Int31()), - }, + ChannelStateBounds: remoteStateBounds, + CommitmentParams: remoteRenderingParams, MultiSigKey: keychain.KeyDescriptor{ PubKey: privKey.PubKey(), KeyLocator: keychain.KeyLocator{ diff --git a/channeldb/db_test.go b/channeldb/db_test.go index 025bf1261..d8113db83 100644 --- a/channeldb/db_test.go +++ b/channeldb/db_test.go @@ -292,6 +292,10 @@ func genRandomChannelShell() (*ChannelShell, error) { } shaChainProducer := shachain.NewRevocationProducer(*revRoot) + commitParams := CommitmentParams{ + CsvDelay: uint16(rand.Int63()), + } + return &ChannelShell{ NodeAddrs: []net.Addr{&net.TCPAddr{ IP: net.ParseIP("127.0.0.1"), @@ -306,9 +310,7 @@ func genRandomChannelShell() (*ChannelShell, error) { ), IdentityPub: pub, LocalChanCfg: ChannelConfig{ - ChannelConstraints: ChannelConstraints{ - CsvDelay: uint16(rand.Int63()), - }, + CommitmentParams: commitParams, PaymentBasePoint: keychain.KeyDescriptor{ KeyLocator: keychain.KeyLocator{ Family: keychain.KeyFamily(rand.Int63()), diff --git a/contractcourt/breach_arbitrator_test.go b/contractcourt/breach_arbitrator_test.go index f2883db4e..6a1865444 100644 --- a/contractcourt/breach_arbitrator_test.go +++ b/contractcourt/breach_arbitrator_test.go @@ -2178,13 +2178,15 @@ func createInitChannels(t *testing.T) ( fundingTxIn := wire.NewTxIn(prevOut, nil, nil) aliceCfg := channeldb.ChannelConfig{ - ChannelConstraints: channeldb.ChannelConstraints{ - DustLimit: aliceDustLimit, + ChannelStateBounds: channeldb.ChannelStateBounds{ MaxPendingAmount: lnwire.MilliSatoshi(rand.Int63()), ChanReserve: 0, MinHTLC: 0, MaxAcceptedHtlcs: uint16(rand.Int31()), - CsvDelay: uint16(csvTimeoutAlice), + }, + CommitmentParams: channeldb.CommitmentParams{ + DustLimit: aliceDustLimit, + CsvDelay: uint16(csvTimeoutAlice), }, MultiSigKey: keychain.KeyDescriptor{ PubKey: aliceKeyPub, @@ -2203,13 +2205,15 @@ func createInitChannels(t *testing.T) ( }, } bobCfg := channeldb.ChannelConfig{ - ChannelConstraints: channeldb.ChannelConstraints{ - DustLimit: bobDustLimit, + ChannelStateBounds: channeldb.ChannelStateBounds{ MaxPendingAmount: lnwire.MilliSatoshi(rand.Int63()), ChanReserve: 0, MinHTLC: 0, MaxAcceptedHtlcs: uint16(rand.Int31()), - CsvDelay: uint16(csvTimeoutBob), + }, + CommitmentParams: channeldb.CommitmentParams{ + DustLimit: bobDustLimit, + CsvDelay: uint16(csvTimeoutBob), }, MultiSigKey: keychain.KeyDescriptor{ PubKey: bobKeyPub, diff --git a/funding/manager.go b/funding/manager.go index 7fd0e9b11..360578453 100644 --- a/funding/manager.go +++ b/funding/manager.go @@ -1671,16 +1671,18 @@ func (f *Manager) fundeeProcessOpenChannel(peer lnpeer.Peer, // We'll also validate and apply all the constraints the initiating // party is attempting to dictate for our commitment transaction. - channelConstraints := &channeldb.ChannelConstraints{ - DustLimit: msg.DustLimit, + stateBounds := &channeldb.ChannelStateBounds{ ChanReserve: msg.ChannelReserve, MaxPendingAmount: msg.MaxValueInFlight, MinHTLC: msg.HtlcMinimum, MaxAcceptedHtlcs: msg.MaxAcceptedHTLCs, - CsvDelay: msg.CsvDelay, + } + commitParams := &channeldb.CommitmentParams{ + DustLimit: msg.DustLimit, + CsvDelay: msg.CsvDelay, } err = reservation.CommitConstraints( - channelConstraints, f.cfg.MaxLocalCSVDelay, true, + stateBounds, commitParams, f.cfg.MaxLocalCSVDelay, true, ) if err != nil { log.Errorf("Unacceptable channel constraints: %v", err) @@ -1780,7 +1782,7 @@ func (f *Manager) fundeeProcessOpenChannel(peer lnpeer.Peer, // interactively. ourContribution := reservation.OurContribution() forwardingPolicy := f.defaultForwardingPolicy( - ourContribution.ChannelConstraints, + ourContribution.ChannelStateBounds, ) // Once the reservation has been created successfully, we add it to @@ -1810,37 +1812,41 @@ func (f *Manager) fundeeProcessOpenChannel(peer lnpeer.Peer, // Update the timestamp once the fundingOpenMsg has been handled. defer resCtx.updateTimestamp() + cfg := channeldb.ChannelConfig{ + ChannelStateBounds: channeldb.ChannelStateBounds{ + MaxPendingAmount: remoteMaxValue, + ChanReserve: chanReserve, + MinHTLC: minHtlc, + MaxAcceptedHtlcs: maxHtlcs, + }, + CommitmentParams: channeldb.CommitmentParams{ + DustLimit: msg.DustLimit, + CsvDelay: remoteCsvDelay, + }, + MultiSigKey: keychain.KeyDescriptor{ + PubKey: copyPubKey(msg.FundingKey), + }, + RevocationBasePoint: keychain.KeyDescriptor{ + PubKey: copyPubKey(msg.RevocationPoint), + }, + PaymentBasePoint: keychain.KeyDescriptor{ + PubKey: copyPubKey(msg.PaymentPoint), + }, + DelayBasePoint: keychain.KeyDescriptor{ + PubKey: copyPubKey(msg.DelayedPaymentPoint), + }, + HtlcBasePoint: keychain.KeyDescriptor{ + PubKey: copyPubKey(msg.HtlcPoint), + }, + } + // With our parameters set, we'll now process their contribution so we // can move the funding workflow ahead. remoteContribution := &lnwallet.ChannelContribution{ FundingAmount: amt, FirstCommitmentPoint: msg.FirstCommitmentPoint, - ChannelConfig: &channeldb.ChannelConfig{ - ChannelConstraints: channeldb.ChannelConstraints{ - DustLimit: msg.DustLimit, - MaxPendingAmount: remoteMaxValue, - ChanReserve: chanReserve, - MinHTLC: minHtlc, - MaxAcceptedHtlcs: maxHtlcs, - CsvDelay: remoteCsvDelay, - }, - MultiSigKey: keychain.KeyDescriptor{ - PubKey: copyPubKey(msg.FundingKey), - }, - RevocationBasePoint: keychain.KeyDescriptor{ - PubKey: copyPubKey(msg.RevocationPoint), - }, - PaymentBasePoint: keychain.KeyDescriptor{ - PubKey: copyPubKey(msg.PaymentPoint), - }, - DelayBasePoint: keychain.KeyDescriptor{ - PubKey: copyPubKey(msg.DelayedPaymentPoint), - }, - HtlcBasePoint: keychain.KeyDescriptor{ - PubKey: copyPubKey(msg.HtlcPoint), - }, - }, - UpfrontShutdown: msg.UpfrontShutdownScript, + ChannelConfig: &cfg, + UpfrontShutdown: msg.UpfrontShutdownScript, } if resCtx.reservation.IsTaproot() { @@ -1867,8 +1873,12 @@ func (f *Manager) fundeeProcessOpenChannel(peer lnpeer.Peer, log.Infof("Sending fundingResp for pending_id(%x)", msg.PendingChannelID) - log.Debugf("Remote party accepted commitment constraints: %v", - spew.Sdump(remoteContribution.ChannelConfig.ChannelConstraints)) + bounds := remoteContribution.ChannelConfig.ChannelStateBounds + log.Debugf("Remote party accepted channel state space bounds: %v", + spew.Sdump(bounds)) + params := remoteContribution.ChannelConfig.CommitmentParams + log.Debugf("Remote party accepted commitment rendering params: %v", + spew.Sdump(params)) // With the initiator's contribution recorded, respond with our // contribution in the next message of the workflow. @@ -2036,16 +2046,18 @@ func (f *Manager) funderProcessAcceptChannel(peer lnpeer.Peer, // required confirmations, and also the set of channel constraints // they've specified for commitment states we can create. resCtx.reservation.SetNumConfsRequired(uint16(minDepth)) - channelConstraints := &channeldb.ChannelConstraints{ - DustLimit: msg.DustLimit, + bounds := channeldb.ChannelStateBounds{ ChanReserve: msg.ChannelReserve, MaxPendingAmount: msg.MaxValueInFlight, MinHTLC: msg.HtlcMinimum, MaxAcceptedHtlcs: msg.MaxAcceptedHTLCs, - CsvDelay: msg.CsvDelay, + } + commitParams := channeldb.CommitmentParams{ + DustLimit: msg.DustLimit, + CsvDelay: msg.CsvDelay, } err = resCtx.reservation.CommitConstraints( - channelConstraints, resCtx.maxLocalCsv, false, + &bounds, &commitParams, resCtx.maxLocalCsv, false, ) if err != nil { log.Warnf("Unacceptable channel constraints: %v", err) @@ -2053,38 +2065,42 @@ func (f *Manager) funderProcessAcceptChannel(peer lnpeer.Peer, return } + cfg := channeldb.ChannelConfig{ + ChannelStateBounds: channeldb.ChannelStateBounds{ + MaxPendingAmount: resCtx.remoteMaxValue, + ChanReserve: resCtx.remoteChanReserve, + MinHTLC: resCtx.remoteMinHtlc, + MaxAcceptedHtlcs: resCtx.remoteMaxHtlcs, + }, + CommitmentParams: channeldb.CommitmentParams{ + DustLimit: msg.DustLimit, + CsvDelay: resCtx.remoteCsvDelay, + }, + MultiSigKey: keychain.KeyDescriptor{ + PubKey: copyPubKey(msg.FundingKey), + }, + RevocationBasePoint: keychain.KeyDescriptor{ + PubKey: copyPubKey(msg.RevocationPoint), + }, + PaymentBasePoint: keychain.KeyDescriptor{ + PubKey: copyPubKey(msg.PaymentPoint), + }, + DelayBasePoint: keychain.KeyDescriptor{ + PubKey: copyPubKey(msg.DelayedPaymentPoint), + }, + HtlcBasePoint: keychain.KeyDescriptor{ + PubKey: copyPubKey(msg.HtlcPoint), + }, + } + // The remote node has responded with their portion of the channel // contribution. At this point, we can process their contribution which // allows us to construct and sign both the commitment transaction, and // the funding transaction. remoteContribution := &lnwallet.ChannelContribution{ FirstCommitmentPoint: msg.FirstCommitmentPoint, - ChannelConfig: &channeldb.ChannelConfig{ - ChannelConstraints: channeldb.ChannelConstraints{ - DustLimit: msg.DustLimit, - MaxPendingAmount: resCtx.remoteMaxValue, - ChanReserve: resCtx.remoteChanReserve, - MinHTLC: resCtx.remoteMinHtlc, - MaxAcceptedHtlcs: resCtx.remoteMaxHtlcs, - CsvDelay: resCtx.remoteCsvDelay, - }, - MultiSigKey: keychain.KeyDescriptor{ - PubKey: copyPubKey(msg.FundingKey), - }, - RevocationBasePoint: keychain.KeyDescriptor{ - PubKey: copyPubKey(msg.RevocationPoint), - }, - PaymentBasePoint: keychain.KeyDescriptor{ - PubKey: copyPubKey(msg.PaymentPoint), - }, - DelayBasePoint: keychain.KeyDescriptor{ - PubKey: copyPubKey(msg.DelayedPaymentPoint), - }, - HtlcBasePoint: keychain.KeyDescriptor{ - PubKey: copyPubKey(msg.HtlcPoint), - }, - }, - UpfrontShutdown: msg.UpfrontShutdownScript, + ChannelConfig: &cfg, + UpfrontShutdown: msg.UpfrontShutdownScript, } if resCtx.reservation.IsTaproot() { @@ -2149,8 +2165,12 @@ func (f *Manager) funderProcessAcceptChannel(peer lnpeer.Peer, log.Infof("pendingChan(%x): remote party proposes num_confs=%v, "+ "csv_delay=%v", pendingChanID[:], msg.MinAcceptDepth, msg.CsvDelay) - log.Debugf("Remote party accepted commitment constraints: %v", - spew.Sdump(remoteContribution.ChannelConfig.ChannelConstraints)) + bounds = remoteContribution.ChannelConfig.ChannelStateBounds + log.Debugf("Remote party accepted channel state space bounds: %v", + spew.Sdump(bounds)) + commitParams = remoteContribution.ChannelConfig.CommitmentParams + log.Debugf("Remote party accepted commitment rendering params: %v", + spew.Sdump(commitParams)) // If the user requested funding through a PSBT, we cannot directly // continue now and need to wait for the fully funded and signed PSBT @@ -4070,7 +4090,7 @@ func (f *Manager) ensureInitialForwardingPolicy(chanID lnwire.ChannelID, "falling back to default values: %v", err) forwardingPolicy = f.defaultForwardingPolicy( - channel.LocalChanCfg.ChannelConstraints, + channel.LocalChanCfg.ChannelStateBounds, ) needDBUpdate = true } @@ -4695,7 +4715,7 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) { // useBaseFee or useFeeRate are false the client did not provide fee // values hence we assume default fee settings from the config. forwardingPolicy := f.defaultForwardingPolicy( - ourContribution.ChannelConstraints, + ourContribution.ChannelStateBounds, ) if baseFee != nil { forwardingPolicy.BaseFee = lnwire.MilliSatoshi(*baseFee) @@ -4750,16 +4770,18 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) { defer resCtx.updateTimestamp() // Check the sanity of the selected channel constraints. - channelConstraints := &channeldb.ChannelConstraints{ - DustLimit: ourDustLimit, + bounds := &channeldb.ChannelStateBounds{ ChanReserve: chanReserve, MaxPendingAmount: maxValue, MinHTLC: minHtlcIn, MaxAcceptedHtlcs: maxHtlcs, - CsvDelay: remoteCsvDelay, + } + commitParams := &channeldb.CommitmentParams{ + DustLimit: ourDustLimit, + CsvDelay: remoteCsvDelay, } err = lnwallet.VerifyConstraints( - channelConstraints, resCtx.maxLocalCsv, capacity, + bounds, commitParams, resCtx.maxLocalCsv, capacity, ) if err != nil { _, reserveErr := f.cancelReservationCtx(peerKey, chanID, false) @@ -5032,11 +5054,11 @@ func copyPubKey(pub *btcec.PublicKey) *btcec.PublicKey { // defaultForwardingPolicy returns the default forwarding policy based on the // default routing policy and our local channel constraints. func (f *Manager) defaultForwardingPolicy( - constraints channeldb.ChannelConstraints) *models.ForwardingPolicy { + bounds channeldb.ChannelStateBounds) *models.ForwardingPolicy { return &models.ForwardingPolicy{ - MinHTLCOut: constraints.MinHTLC, - MaxHTLC: constraints.MaxPendingAmount, + MinHTLCOut: bounds.MinHTLC, + MaxHTLC: bounds.MaxPendingAmount, BaseFee: f.cfg.DefaultRoutingPolicy.BaseFee, FeeRate: f.cfg.DefaultRoutingPolicy.FeeRate, TimeLockDelta: f.cfg.DefaultRoutingPolicy.TimeLockDelta, diff --git a/htlcswitch/test_utils.go b/htlcswitch/test_utils.go index 9a72197ec..5243eebe0 100644 --- a/htlcswitch/test_utils.go +++ b/htlcswitch/test_utils.go @@ -138,24 +138,28 @@ func createTestChannel(t *testing.T, alicePrivKey, bobPrivKey []byte, csvTimeoutBob := uint32(4) isAliceInitiator := true - aliceConstraints := &channeldb.ChannelConstraints{ - DustLimit: btcutil.Amount(200), + aliceBounds := channeldb.ChannelStateBounds{ MaxPendingAmount: lnwire.NewMSatFromSatoshis( channelCapacity), ChanReserve: aliceReserve, MinHTLC: 0, MaxAcceptedHtlcs: input.MaxHTLCNumber / 2, - CsvDelay: uint16(csvTimeoutAlice), + } + aliceCommitParams := channeldb.CommitmentParams{ + DustLimit: btcutil.Amount(200), + CsvDelay: uint16(csvTimeoutAlice), } - bobConstraints := &channeldb.ChannelConstraints{ - DustLimit: btcutil.Amount(800), + bobBounds := channeldb.ChannelStateBounds{ MaxPendingAmount: lnwire.NewMSatFromSatoshis( channelCapacity), ChanReserve: bobReserve, MinHTLC: 0, MaxAcceptedHtlcs: input.MaxHTLCNumber / 2, - CsvDelay: uint16(csvTimeoutBob), + } + bobCommitParams := channeldb.CommitmentParams{ + DustLimit: btcutil.Amount(800), + CsvDelay: uint16(csvTimeoutBob), } var hash [sha256.Size]byte @@ -172,7 +176,8 @@ func createTestChannel(t *testing.T, alicePrivKey, bobPrivKey []byte, fundingTxIn := wire.NewTxIn(prevOut, nil, nil) aliceCfg := channeldb.ChannelConfig{ - ChannelConstraints: *aliceConstraints, + ChannelStateBounds: aliceBounds, + CommitmentParams: aliceCommitParams, MultiSigKey: keychain.KeyDescriptor{ PubKey: aliceKeyPub, }, @@ -190,7 +195,8 @@ func createTestChannel(t *testing.T, alicePrivKey, bobPrivKey []byte, }, } bobCfg := channeldb.ChannelConfig{ - ChannelConstraints: *bobConstraints, + ChannelStateBounds: bobBounds, + CommitmentParams: bobCommitParams, MultiSigKey: keychain.KeyDescriptor{ PubKey: bobKeyPub, }, diff --git a/lnwallet/reservation.go b/lnwallet/reservation.go index 1c6dbbabe..529db1141 100644 --- a/lnwallet/reservation.go +++ b/lnwallet/reservation.go @@ -501,29 +501,34 @@ func (r *ChannelReservation) IsTaproot() bool { // of satoshis that can be transferred in a single commitment. This function // will also attempt to verify the constraints for sanity, returning an error // if the parameters are seemed unsound. -func (r *ChannelReservation) CommitConstraints(c *channeldb.ChannelConstraints, - maxLocalCSVDelay uint16, responder bool) error { +func (r *ChannelReservation) CommitConstraints( + bounds *channeldb.ChannelStateBounds, + commitParams *channeldb.CommitmentParams, + maxLocalCSVDelay uint16, + responder bool) error { r.Lock() defer r.Unlock() // First, verify the sanity of the channel constraints. - err := VerifyConstraints(c, maxLocalCSVDelay, r.partialState.Capacity) + err := VerifyConstraints( + bounds, commitParams, maxLocalCSVDelay, r.partialState.Capacity, + ) if err != nil { return err } // Our dust limit should always be less than or equal to our proposed // channel reserve. - if responder && r.ourContribution.DustLimit > c.ChanReserve { - r.ourContribution.DustLimit = c.ChanReserve + if responder && r.ourContribution.DustLimit > bounds.ChanReserve { + r.ourContribution.DustLimit = bounds.ChanReserve } - r.ourContribution.ChanReserve = c.ChanReserve - r.ourContribution.MaxPendingAmount = c.MaxPendingAmount - r.ourContribution.MinHTLC = c.MinHTLC - r.ourContribution.MaxAcceptedHtlcs = c.MaxAcceptedHtlcs - r.ourContribution.CsvDelay = c.CsvDelay + r.ourContribution.ChanReserve = bounds.ChanReserve + r.ourContribution.MaxPendingAmount = bounds.MaxPendingAmount + r.ourContribution.MinHTLC = bounds.MinHTLC + r.ourContribution.MaxAcceptedHtlcs = bounds.MaxAcceptedHtlcs + r.ourContribution.CsvDelay = commitParams.CsvDelay return nil } @@ -805,62 +810,75 @@ func (r *ChannelReservation) Cancel() error { // VerifyConstraints is a helper function that can be used to check the sanity // of various channel constraints. -func VerifyConstraints(c *channeldb.ChannelConstraints, - maxLocalCSVDelay uint16, channelCapacity btcutil.Amount) error { +func VerifyConstraints(bounds *channeldb.ChannelStateBounds, + commitParams *channeldb.CommitmentParams, maxLocalCSVDelay uint16, + channelCapacity btcutil.Amount) error { // Fail if the csv delay for our funds exceeds our maximum. - if c.CsvDelay > maxLocalCSVDelay { - return ErrCsvDelayTooLarge(c.CsvDelay, maxLocalCSVDelay) + if commitParams.CsvDelay > maxLocalCSVDelay { + return ErrCsvDelayTooLarge( + commitParams.CsvDelay, maxLocalCSVDelay, + ) } // The channel reserve should always be greater or equal to the dust // limit. The reservation request should be denied if otherwise. - if c.DustLimit > c.ChanReserve { - return ErrChanReserveTooSmall(c.ChanReserve, c.DustLimit) + if commitParams.DustLimit > bounds.ChanReserve { + return ErrChanReserveTooSmall( + bounds.ChanReserve, commitParams.DustLimit, + ) } // Validate against the maximum-sized witness script dust limit, and // also ensure that the DustLimit is not too large. maxWitnessLimit := DustLimitForSize(input.UnknownWitnessSize) - if c.DustLimit < maxWitnessLimit || c.DustLimit > 3*maxWitnessLimit { - return ErrInvalidDustLimit(c.DustLimit) + if commitParams.DustLimit < maxWitnessLimit || + commitParams.DustLimit > 3*maxWitnessLimit { + + return ErrInvalidDustLimit(commitParams.DustLimit) } // Fail if we consider the channel reserve to be too large. We // currently fail if it is greater than 20% of the channel capacity. maxChanReserve := channelCapacity / 5 - if c.ChanReserve > maxChanReserve { - return ErrChanReserveTooLarge(c.ChanReserve, maxChanReserve) + if bounds.ChanReserve > maxChanReserve { + return ErrChanReserveTooLarge( + bounds.ChanReserve, maxChanReserve, + ) } // Fail if the minimum HTLC value is too large. If this is too large, // the channel won't be useful for sending small payments. This limit // is currently set to maxValueInFlight, effectively letting the remote // setting this as large as it wants. - if c.MinHTLC > c.MaxPendingAmount { - return ErrMinHtlcTooLarge(c.MinHTLC, c.MaxPendingAmount) + if bounds.MinHTLC > bounds.MaxPendingAmount { + return ErrMinHtlcTooLarge( + bounds.MinHTLC, bounds.MaxPendingAmount, + ) } // Fail if maxHtlcs is above the maximum allowed number of 483. This // number is specified in BOLT-02. - if c.MaxAcceptedHtlcs > uint16(input.MaxHTLCNumber/2) { + if bounds.MaxAcceptedHtlcs > uint16(input.MaxHTLCNumber/2) { return ErrMaxHtlcNumTooLarge( - c.MaxAcceptedHtlcs, uint16(input.MaxHTLCNumber/2), + bounds.MaxAcceptedHtlcs, uint16(input.MaxHTLCNumber/2), ) } // Fail if we consider maxHtlcs too small. If this is too small we // cannot offer many HTLCs to the remote. const minNumHtlc = 5 - if c.MaxAcceptedHtlcs < minNumHtlc { - return ErrMaxHtlcNumTooSmall(c.MaxAcceptedHtlcs, minNumHtlc) + if bounds.MaxAcceptedHtlcs < minNumHtlc { + return ErrMaxHtlcNumTooSmall( + bounds.MaxAcceptedHtlcs, minNumHtlc, + ) } // Fail if we consider maxValueInFlight too small. We currently require // the remote to at least allow minNumHtlc * minHtlc in flight. - if c.MaxPendingAmount < minNumHtlc*c.MinHTLC { + if bounds.MaxPendingAmount < minNumHtlc*bounds.MinHTLC { return ErrMaxValueInFlightTooSmall( - c.MaxPendingAmount, minNumHtlc*c.MinHTLC, + bounds.MaxPendingAmount, minNumHtlc*bounds.MinHTLC, ) } diff --git a/lnwallet/test/test_interface.go b/lnwallet/test/test_interface.go index c3d26f6cf..dfabdc741 100644 --- a/lnwallet/test/test_interface.go +++ b/lnwallet/test/test_interface.go @@ -422,16 +422,18 @@ func testDualFundingReservationWorkflow(miner *rpctest.Harness, aliceChanReservation, err := alice.InitChannelReservation(aliceReq) require.NoError(t, err, "unable to initialize funding reservation") aliceChanReservation.SetNumConfsRequired(numReqConfs) - channelConstraints := &channeldb.ChannelConstraints{ - DustLimit: lnwallet.DustLimitUnknownWitness(), + bounds := &channeldb.ChannelStateBounds{ ChanReserve: fundingAmount / 100, MaxPendingAmount: lnwire.NewMSatFromSatoshis(fundingAmount), MinHTLC: 1, MaxAcceptedHtlcs: input.MaxHTLCNumber / 2, - CsvDelay: csvDelay, + } + commitParams := &channeldb.CommitmentParams{ + DustLimit: lnwallet.DustLimitUnknownWitness(), + CsvDelay: csvDelay, } err = aliceChanReservation.CommitConstraints( - channelConstraints, defaultMaxLocalCsvDelay, false, + bounds, commitParams, defaultMaxLocalCsvDelay, false, ) require.NoError(t, err, "unable to verify constraints") @@ -463,7 +465,7 @@ func testDualFundingReservationWorkflow(miner *rpctest.Harness, bobChanReservation, err := bob.InitChannelReservation(bobReq) require.NoError(t, err, "bob unable to init channel reservation") err = bobChanReservation.CommitConstraints( - channelConstraints, defaultMaxLocalCsvDelay, true, + bounds, commitParams, defaultMaxLocalCsvDelay, true, ) require.NoError(t, err, "unable to verify constraints") bobChanReservation.SetNumConfsRequired(numReqConfs) @@ -827,16 +829,18 @@ func testSingleFunderReservationWorkflow(miner *rpctest.Harness, aliceChanReservation, err := alice.InitChannelReservation(aliceReq) require.NoError(t, err, "unable to init channel reservation") aliceChanReservation.SetNumConfsRequired(numReqConfs) - channelConstraints := &channeldb.ChannelConstraints{ - DustLimit: lnwallet.DustLimitUnknownWitness(), + bounds := &channeldb.ChannelStateBounds{ ChanReserve: fundingAmt / 100, MaxPendingAmount: lnwire.NewMSatFromSatoshis(fundingAmt), MinHTLC: 1, MaxAcceptedHtlcs: input.MaxHTLCNumber / 2, - CsvDelay: csvDelay, + } + commitParams := &channeldb.CommitmentParams{ + DustLimit: lnwallet.DustLimitUnknownWitness(), + CsvDelay: csvDelay, } err = aliceChanReservation.CommitConstraints( - channelConstraints, defaultMaxLocalCsvDelay, false, + bounds, commitParams, defaultMaxLocalCsvDelay, false, ) require.NoError(t, err, "unable to verify constraints") @@ -875,7 +879,7 @@ func testSingleFunderReservationWorkflow(miner *rpctest.Harness, bobChanReservation, err := bob.InitChannelReservation(bobReq) require.NoError(t, err, "unable to create bob reservation") err = bobChanReservation.CommitConstraints( - channelConstraints, defaultMaxLocalCsvDelay, true, + bounds, commitParams, defaultMaxLocalCsvDelay, true, ) require.NoError(t, err, "unable to verify constraints") bobChanReservation.SetNumConfsRequired(numReqConfs) diff --git a/lnwallet/test_utils.go b/lnwallet/test_utils.go index 29213bb7f..0e5d52723 100644 --- a/lnwallet/test_utils.go +++ b/lnwallet/test_utils.go @@ -150,13 +150,15 @@ func CreateTestChannels(t *testing.T, chanType channeldb.ChannelType, } aliceCfg := channeldb.ChannelConfig{ - ChannelConstraints: channeldb.ChannelConstraints{ - DustLimit: aliceDustLimit, + ChannelStateBounds: channeldb.ChannelStateBounds{ MaxPendingAmount: lnwire.NewMSatFromSatoshis(channelCapacity), ChanReserve: channelCapacity / 100, MinHTLC: 0, MaxAcceptedHtlcs: input.MaxHTLCNumber / 2, - CsvDelay: uint16(csvTimeoutAlice), + }, + CommitmentParams: channeldb.CommitmentParams{ + DustLimit: aliceDustLimit, + CsvDelay: uint16(csvTimeoutAlice), }, MultiSigKey: keychain.KeyDescriptor{ PubKey: aliceKeys[0].PubKey(), @@ -175,13 +177,15 @@ func CreateTestChannels(t *testing.T, chanType channeldb.ChannelType, }, } bobCfg := channeldb.ChannelConfig{ - ChannelConstraints: channeldb.ChannelConstraints{ - DustLimit: bobDustLimit, + ChannelStateBounds: channeldb.ChannelStateBounds{ MaxPendingAmount: lnwire.NewMSatFromSatoshis(channelCapacity), ChanReserve: channelCapacity / 100, MinHTLC: 0, MaxAcceptedHtlcs: input.MaxHTLCNumber / 2, - CsvDelay: uint16(csvTimeoutBob), + }, + CommitmentParams: channeldb.CommitmentParams{ + DustLimit: bobDustLimit, + CsvDelay: uint16(csvTimeoutBob), }, MultiSigKey: keychain.KeyDescriptor{ PubKey: bobKeys[0].PubKey(), diff --git a/lnwallet/transactions_test.go b/lnwallet/transactions_test.go index d2a2a448b..4c7fbed53 100644 --- a/lnwallet/transactions_test.go +++ b/lnwallet/transactions_test.go @@ -603,14 +603,14 @@ func testSpendValidation(t *testing.T, tweakless bool) { dustLimit := DustLimitForSize(input.UnknownWitnessSize) aliceChanCfg := &channeldb.ChannelConfig{ - ChannelConstraints: channeldb.ChannelConstraints{ + CommitmentParams: channeldb.CommitmentParams{ DustLimit: dustLimit, CsvDelay: csvTimeout, }, } bobChanCfg := &channeldb.ChannelConfig{ - ChannelConstraints: channeldb.ChannelConstraints{ + CommitmentParams: channeldb.CommitmentParams{ DustLimit: dustLimit, CsvDelay: csvTimeout, }, @@ -834,15 +834,17 @@ func createTestChannelsForVectors(tc *testContext, chanType channeldb.ChannelTyp // Define channel configurations. remoteCfg := channeldb.ChannelConfig{ - ChannelConstraints: channeldb.ChannelConstraints{ - DustLimit: tc.dustLimit, + ChannelStateBounds: channeldb.ChannelStateBounds{ MaxPendingAmount: lnwire.NewMSatFromSatoshis( tc.fundingAmount, ), ChanReserve: 0, MinHTLC: 0, MaxAcceptedHtlcs: input.MaxHTLCNumber / 2, - CsvDelay: tc.localCsvDelay, + }, + CommitmentParams: channeldb.CommitmentParams{ + DustLimit: tc.dustLimit, + CsvDelay: tc.localCsvDelay, }, MultiSigKey: keychain.KeyDescriptor{ PubKey: tc.remoteFundingPrivkey.PubKey(), @@ -861,15 +863,17 @@ func createTestChannelsForVectors(tc *testContext, chanType channeldb.ChannelTyp }, } localCfg := channeldb.ChannelConfig{ - ChannelConstraints: channeldb.ChannelConstraints{ - DustLimit: tc.dustLimit, + ChannelStateBounds: channeldb.ChannelStateBounds{ MaxPendingAmount: lnwire.NewMSatFromSatoshis( tc.fundingAmount, ), ChanReserve: 0, MinHTLC: 0, MaxAcceptedHtlcs: input.MaxHTLCNumber / 2, - CsvDelay: tc.localCsvDelay, + }, + CommitmentParams: channeldb.CommitmentParams{ + DustLimit: tc.dustLimit, + CsvDelay: tc.localCsvDelay, }, MultiSigKey: keychain.KeyDescriptor{ PubKey: tc.localFundingPrivkey.PubKey(), diff --git a/lnwallet/wallet.go b/lnwallet/wallet.go index a56bf1c21..90a0bea2d 100644 --- a/lnwallet/wallet.go +++ b/lnwallet/wallet.go @@ -1379,7 +1379,7 @@ func (l *LightningWallet) initOurContribution(reservation *ChannelReservation, ) reservation.partialState.RevocationProducer = producer - reservation.ourContribution.ChannelConstraints.DustLimit = + reservation.ourContribution.CommitmentParams.DustLimit = DustLimitUnknownWitness() // If taproot channels are active, then we'll generate our verification diff --git a/peer/test_utils.go b/peer/test_utils.go index 8667b04cd..8d1355b18 100644 --- a/peer/test_utils.go +++ b/peer/test_utils.go @@ -115,13 +115,15 @@ func createTestPeerWithChannel(t *testing.T, updateChan func(a, ) aliceCfg := channeldb.ChannelConfig{ - ChannelConstraints: channeldb.ChannelConstraints{ - DustLimit: aliceDustLimit, + ChannelStateBounds: channeldb.ChannelStateBounds{ MaxPendingAmount: lnwire.MilliSatoshi(rand.Int63()), ChanReserve: btcutil.Amount(rand.Int63()), MinHTLC: lnwire.MilliSatoshi(rand.Int63()), MaxAcceptedHtlcs: uint16(rand.Int31()), - CsvDelay: uint16(csvTimeoutAlice), + }, + CommitmentParams: channeldb.CommitmentParams{ + DustLimit: aliceDustLimit, + CsvDelay: uint16(csvTimeoutAlice), }, MultiSigKey: keychain.KeyDescriptor{ PubKey: aliceKeyPub, @@ -140,13 +142,15 @@ func createTestPeerWithChannel(t *testing.T, updateChan func(a, }, } bobCfg := channeldb.ChannelConfig{ - ChannelConstraints: channeldb.ChannelConstraints{ - DustLimit: bobDustLimit, + ChannelStateBounds: channeldb.ChannelStateBounds{ MaxPendingAmount: lnwire.MilliSatoshi(rand.Int63()), ChanReserve: btcutil.Amount(rand.Int63()), MinHTLC: lnwire.MilliSatoshi(rand.Int63()), MaxAcceptedHtlcs: uint16(rand.Int31()), - CsvDelay: uint16(csvTimeoutBob), + }, + CommitmentParams: channeldb.CommitmentParams{ + DustLimit: bobDustLimit, + CsvDelay: uint16(csvTimeoutBob), }, MultiSigKey: keychain.KeyDescriptor{ PubKey: bobKeyPub, diff --git a/routing/localchans/manager.go b/routing/localchans/manager.go index 930b4c96b..f0f9b88de 100644 --- a/routing/localchans/manager.go +++ b/routing/localchans/manager.go @@ -279,7 +279,7 @@ func (r *Manager) getHtlcAmtLimits(tx kvdb.RTx, chanPoint wire.OutPoint) ( // 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.ChannelConstraints.MaxPendingAmount + maxAmt := ch.LocalChanCfg.ChannelStateBounds.MaxPendingAmount return ch.LocalChanCfg.MinHTLC, maxAmt, nil } diff --git a/routing/localchans/manager_test.go b/routing/localchans/manager_test.go index b103ef31f..7594eef04 100644 --- a/routing/localchans/manager_test.go +++ b/routing/localchans/manager_test.go @@ -125,14 +125,14 @@ func TestManager(t *testing.T) { return &channeldb.OpenChannel{}, channeldb.ErrChannelNotFound } - constraints := channeldb.ChannelConstraints{ + bounds := channeldb.ChannelStateBounds{ MaxPendingAmount: maxPendingAmount, MinHTLC: minHTLC, } return &channeldb.OpenChannel{ LocalChanCfg: channeldb.ChannelConfig{ - ChannelConstraints: constraints, + ChannelStateBounds: bounds, }, }, nil } From 22e34702d88b2907748bef1c957d33066e1a27f4 Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Wed, 31 Jul 2024 13:15:02 -0700 Subject: [PATCH 2/2] funding: replace newly edited log values with lazier variants --- funding/manager.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/funding/manager.go b/funding/manager.go index 360578453..8ad16005c 100644 --- a/funding/manager.go +++ b/funding/manager.go @@ -1875,10 +1875,10 @@ func (f *Manager) fundeeProcessOpenChannel(peer lnpeer.Peer, msg.PendingChannelID) bounds := remoteContribution.ChannelConfig.ChannelStateBounds log.Debugf("Remote party accepted channel state space bounds: %v", - spew.Sdump(bounds)) + lnutils.SpewLogClosure(bounds)) params := remoteContribution.ChannelConfig.CommitmentParams log.Debugf("Remote party accepted commitment rendering params: %v", - spew.Sdump(params)) + lnutils.SpewLogClosure(params)) // With the initiator's contribution recorded, respond with our // contribution in the next message of the workflow. @@ -2167,10 +2167,10 @@ func (f *Manager) funderProcessAcceptChannel(peer lnpeer.Peer, msg.CsvDelay) bounds = remoteContribution.ChannelConfig.ChannelStateBounds log.Debugf("Remote party accepted channel state space bounds: %v", - spew.Sdump(bounds)) + lnutils.SpewLogClosure(bounds)) commitParams = remoteContribution.ChannelConfig.CommitmentParams log.Debugf("Remote party accepted commitment rendering params: %v", - spew.Sdump(commitParams)) + lnutils.SpewLogClosure(commitParams)) // If the user requested funding through a PSBT, we cannot directly // continue now and need to wait for the fully funded and signed PSBT