Merge pull request #5274 from halseth/anchors-reserved-value-max

[anchors] cap value reserved for anchor fee bumping
This commit is contained in:
Olaoluwa Osuntokun 2021-05-12 16:19:57 -07:00 committed by GitHub
commit 6a2fb316ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 78 additions and 13 deletions

@ -1,3 +1,5 @@
// +build !rpctest
package lncfg package lncfg
// ProtocolOptions is a struct that we use to be able to test backwards // ProtocolOptions is a struct that we use to be able to test backwards
@ -18,8 +20,9 @@ type ProtocolOptions struct {
// mini. // mini.
WumboChans bool `long:"wumbo-channels" description:"if set, then lnd will create and accept requests for channels larger chan 0.16 BTC"` WumboChans bool `long:"wumbo-channels" description:"if set, then lnd will create and accept requests for channels larger chan 0.16 BTC"`
// Anchors enables anchor commitments. // NoAnchors should be set if we don't want to support opening or accepting
Anchors bool `long:"anchors" description:"enable support for anchor commitments"` // channels having the anchor commitment type.
NoAnchors bool `long:"no-anchors" description:"disable support for anchor commitments"`
} }
// Wumbo returns true if lnd should permit the creation and acceptance of wumbo // Wumbo returns true if lnd should permit the creation and acceptance of wumbo
@ -31,5 +34,5 @@ func (l *ProtocolOptions) Wumbo() bool {
// NoAnchorCommitments returns true if we have disabled support for the anchor // NoAnchorCommitments returns true if we have disabled support for the anchor
// commitment type. // commitment type.
func (l *ProtocolOptions) NoAnchorCommitments() bool { func (l *ProtocolOptions) NoAnchorCommitments() bool {
return !l.Anchors return l.NoAnchors
} }

38
lncfg/protocol_rpctest.go Normal file

@ -0,0 +1,38 @@
// +build rpctest
package lncfg
// ProtocolOptions is a struct that we use to be able to test backwards
// compatibility of protocol additions, while defaulting to the latest within
// lnd, or to enable experimental protocol changes.
type ProtocolOptions struct {
// LegacyProtocol is a sub-config that houses all the legacy protocol
// options. These are mostly used for integration tests as most modern
// nodes shuld always run with them on by default.
LegacyProtocol `group:"legacy" namespace:"legacy"`
// ExperimentalProtocol is a sub-config that houses any experimental
// protocol features that also require a build-tag to activate.
ExperimentalProtocol
// WumboChans should be set if we want to enable support for wumbo
// (channels larger than 0.16 BTC) channels, which is the opposite of
// mini.
WumboChans bool `long:"wumbo-channels" description:"if set, then lnd will create and accept requests for channels larger chan 0.16 BTC"`
// Anchors enables anchor commitments.
// TODO(halseth): transition itests to anchors instead!
Anchors bool `long:"anchors" description:"enable support for anchor commitments"`
}
// Wumbo returns true if lnd should permit the creation and acceptance of wumbo
// channels.
func (l *ProtocolOptions) Wumbo() bool {
return l.WumboChans
}
// NoAnchorCommitments returns true if we have disabled support for the anchor
// commitment type.
func (l *ProtocolOptions) NoAnchorCommitments() bool {
return !l.Anchors
}

@ -39,6 +39,13 @@ const (
// TODO(halseth): update constant to target a specific commit size at // TODO(halseth): update constant to target a specific commit size at
// set fee rate. // set fee rate.
anchorChanReservedValue = btcutil.Amount(10_000) anchorChanReservedValue = btcutil.Amount(10_000)
// maxAnchorChanReservedValue is the maximum value we'll reserve for
// anchor channel fee bumping. We cap it at 10 times the per-channel
// amount such that nodes with a high number of channels don't have to
// keep around a very large amount for the unlikely scenario that they
// all close at the same time.
maxAnchorChanReservedValue = 10 * anchorChanReservedValue
) )
var ( var (
@ -597,9 +604,11 @@ func (l *LightningWallet) PsbtFundingVerify(pendingChanID [32]byte,
// If this commit type is an anchor channel we add that to our counter, // If this commit type is an anchor channel we add that to our counter,
// but only if we are contributing funds to the channel. This is done // but only if we are contributing funds to the channel. This is done
// to still allow incoming channels even though we have no UTXOs // to still allow incoming channels even though we have no UTXOs
// available, as in bootstrapping phases. // available, as in bootstrapping phases. We only count public
// channels.
isPublic := pendingReservation.partialState.ChannelFlags&lnwire.FFAnnounceChannel != 0
if pendingReservation.partialState.ChanType.HasAnchors() && if pendingReservation.partialState.ChanType.HasAnchors() &&
intent.LocalFundingAmt() > 0 { intent.LocalFundingAmt() > 0 && isPublic {
numAnchors++ numAnchors++
} }
@ -812,9 +821,11 @@ func (l *LightningWallet) handleFundingReserveRequest(req *InitFundingReserveMsg
// If this commit type is an anchor channel we add that to our counter, // If this commit type is an anchor channel we add that to our counter,
// but only if we are contributing funds to the channel. This is done // but only if we are contributing funds to the channel. This is done
// to still allow incoming channels even though we have no UTXOs // to still allow incoming channels even though we have no UTXOs
// available, as in bootstrapping phases. // available, as in bootstrapping phases. We only count public
// channels.
isPublic := req.Flags&lnwire.FFAnnounceChannel != 0
if req.CommitType == CommitmentTypeAnchorsZeroFeeHtlcTx && if req.CommitType == CommitmentTypeAnchorsZeroFeeHtlcTx &&
fundingIntent.LocalFundingAmt() > 0 { fundingIntent.LocalFundingAmt() > 0 && isPublic {
numAnchors++ numAnchors++
} }
@ -881,8 +892,8 @@ func (l *LightningWallet) handleFundingReserveRequest(req *InitFundingReserveMsg
req.err <- nil req.err <- nil
} }
// currentNumAnchorChans returns the current number of anchor channels the // currentNumAnchorChans returns the current number of non-private anchor
// wallet should be ready to fee bump if needed. // channels the wallet should be ready to fee bump if needed.
func (l *LightningWallet) currentNumAnchorChans() (int, error) { func (l *LightningWallet) currentNumAnchorChans() (int, error) {
// Count all anchor channels that are open or pending // Count all anchor channels that are open or pending
// open, or waiting close. // open, or waiting close.
@ -892,10 +903,22 @@ func (l *LightningWallet) currentNumAnchorChans() (int, error) {
} }
var numAnchors int var numAnchors int
for _, c := range chans { cntChannel := func(c *channeldb.OpenChannel) {
// We skip private channels, as we assume they won't be used
// for routing.
if c.ChannelFlags&lnwire.FFAnnounceChannel == 0 {
return
}
// Count anchor channels.
if c.ChanType.HasAnchors() { if c.ChanType.HasAnchors() {
numAnchors++ numAnchors++
} }
}
for _, c := range chans {
cntChannel(c)
} }
// We also count pending close channels. // We also count pending close channels.
@ -918,9 +941,7 @@ func (l *LightningWallet) currentNumAnchorChans() (int, error) {
continue continue
} }
if c.ChanType.HasAnchors() { cntChannel(c)
numAnchors++
}
} }
return numAnchors, nil return numAnchors, nil
@ -1000,6 +1021,9 @@ func (l *LightningWallet) CheckReservedValue(in []wire.OutPoint,
// We reserve a given amount for each anchor channel. // We reserve a given amount for each anchor channel.
reserved := btcutil.Amount(numAnchorChans) * anchorChanReservedValue reserved := btcutil.Amount(numAnchorChans) * anchorChanReservedValue
if reserved > maxAnchorChanReservedValue {
reserved = maxAnchorChanReservedValue
}
if walletBalance < reserved { if walletBalance < reserved {
walletLog.Debugf("Reserved value=%v above final "+ walletLog.Debugf("Reserved value=%v above final "+