From a0b6a0b00ba8306f55535a058f528641dbec873c Mon Sep 17 00:00:00 2001 From: "Johan T. Halseth" Date: Thu, 6 May 2021 13:24:43 +0200 Subject: [PATCH 1/3] lnwallet: cap value reserved for anchor fee bumping We cap the maximum value we'll reserve for anchor channel fee bumping 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 scanario that they all close at the same time. --- lnwallet/wallet.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lnwallet/wallet.go b/lnwallet/wallet.go index 6d28f91d..dc6d6838 100644 --- a/lnwallet/wallet.go +++ b/lnwallet/wallet.go @@ -39,6 +39,13 @@ const ( // TODO(halseth): update constant to target a specific commit size at // set fee rate. 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 ( @@ -1000,6 +1007,9 @@ func (l *LightningWallet) CheckReservedValue(in []wire.OutPoint, // We reserve a given amount for each anchor channel. reserved := btcutil.Amount(numAnchorChans) * anchorChanReservedValue + if reserved > maxAnchorChanReservedValue { + reserved = maxAnchorChanReservedValue + } if walletBalance < reserved { walletLog.Debugf("Reserved value=%v above final "+ From 8e1087d1cdcbb21b495cffa74ac0afc6c2ffa533 Mon Sep 17 00:00:00 2001 From: "Johan T. Halseth" Date: Mon, 10 May 2021 10:06:23 +0200 Subject: [PATCH 2/3] lwallet: only count public channels towards our reserved value Since private channels (most likely) won't be used for routing other than as last hop, they bear a smaller risk that we must quickly force close them in order to resolve a HTLC up/downstream. In the case where it actually has to be force to resolve a payment (if it is the first/last hop on a routed payment), we can assume that the router will have UTXOs available from the reserved value from the incoming public channel. --- lnwallet/wallet.go | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/lnwallet/wallet.go b/lnwallet/wallet.go index dc6d6838..c61cf8b3 100644 --- a/lnwallet/wallet.go +++ b/lnwallet/wallet.go @@ -604,9 +604,11 @@ func (l *LightningWallet) PsbtFundingVerify(pendingChanID [32]byte, // 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 // 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() && - intent.LocalFundingAmt() > 0 { + intent.LocalFundingAmt() > 0 && isPublic { numAnchors++ } @@ -819,9 +821,11 @@ func (l *LightningWallet) handleFundingReserveRequest(req *InitFundingReserveMsg // 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 // 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 && - fundingIntent.LocalFundingAmt() > 0 { + fundingIntent.LocalFundingAmt() > 0 && isPublic { numAnchors++ } @@ -888,8 +892,8 @@ func (l *LightningWallet) handleFundingReserveRequest(req *InitFundingReserveMsg req.err <- nil } -// currentNumAnchorChans returns the current number of anchor channels the -// wallet should be ready to fee bump if needed. +// currentNumAnchorChans returns the current number of non-private anchor +// channels the wallet should be ready to fee bump if needed. func (l *LightningWallet) currentNumAnchorChans() (int, error) { // Count all anchor channels that are open or pending // open, or waiting close. @@ -899,10 +903,22 @@ func (l *LightningWallet) currentNumAnchorChans() (int, error) { } 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() { numAnchors++ } + + } + + for _, c := range chans { + cntChannel(c) } // We also count pending close channels. @@ -925,9 +941,7 @@ func (l *LightningWallet) currentNumAnchorChans() (int, error) { continue } - if c.ChanType.HasAnchors() { - numAnchors++ - } + cntChannel(c) } return numAnchors, nil From 820e77d574dc75ab3d58cd64c524463e4141f941 Mon Sep 17 00:00:00 2001 From: "Johan T. Halseth" Date: Mon, 10 May 2021 10:16:59 +0200 Subject: [PATCH 3/3] lncfg: make anchor channels by default This commit again enables anchor channels by default. During itests we still keep anchors opt-in, as many of the tests rely on the behaviour of non-anchor channels. --- lncfg/protocol.go | 9 ++++++--- lncfg/protocol_rpctest.go | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 lncfg/protocol_rpctest.go diff --git a/lncfg/protocol.go b/lncfg/protocol.go index 20bad430..afc12968 100644 --- a/lncfg/protocol.go +++ b/lncfg/protocol.go @@ -1,3 +1,5 @@ +// +build !rpctest + package lncfg // ProtocolOptions is a struct that we use to be able to test backwards @@ -18,8 +20,9 @@ type ProtocolOptions struct { // 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. - Anchors bool `long:"anchors" description:"enable support for anchor commitments"` + // NoAnchors should be set if we don't want to support opening or accepting + // 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 @@ -31,5 +34,5 @@ func (l *ProtocolOptions) Wumbo() bool { // NoAnchorCommitments returns true if we have disabled support for the anchor // commitment type. func (l *ProtocolOptions) NoAnchorCommitments() bool { - return !l.Anchors + return l.NoAnchors } diff --git a/lncfg/protocol_rpctest.go b/lncfg/protocol_rpctest.go new file mode 100644 index 00000000..037aec77 --- /dev/null +++ b/lncfg/protocol_rpctest.go @@ -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 +}