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 }