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.
This commit is contained in:
Keagan McClelland 2024-05-09 14:32:45 -07:00
parent b21521ff14
commit e3a9d0acbe
No known key found for this signature in database
GPG key ID: FA7E65C951F12439
15 changed files with 338 additions and 242 deletions

View file

@ -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
}

View file

@ -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.

View file

@ -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{

View file

@ -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()),

View file

@ -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,

View file

@ -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,

View file

@ -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,
},

View file

@ -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,
)
}

View file

@ -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)

View file

@ -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(),

View file

@ -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(),

View file

@ -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

View file

@ -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,

View file

@ -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
}

View file

@ -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
}