Merge pull request #8953 from ProofOfKeags/refactor/lnwallet-channel-channel-constraints-partition

[MICRO]: multi: break ChannelConstraints into two sub-structures
This commit is contained in:
Oliver Gugger 2024-08-05 02:08:52 -06:00 committed by GitHub
commit 11c7e20d0a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
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",
lnutils.SpewLogClosure(bounds))
params := remoteContribution.ChannelConfig.CommitmentParams
log.Debugf("Remote party accepted commitment rendering params: %v",
lnutils.SpewLogClosure(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",
lnutils.SpewLogClosure(bounds))
commitParams = remoteContribution.ChannelConfig.CommitmentParams
log.Debugf("Remote party accepted commitment rendering params: %v",
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
@ -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
}