Merge pull request #6075 from Roasbeef/chan-type-satisfice

funding: always send a channel type in explicit mode
This commit is contained in:
Olaoluwa Osuntokun 2021-12-15 16:39:02 -08:00 committed by GitHub
commit d13246dbc2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 81 additions and 34 deletions

View file

@ -5,6 +5,9 @@
* [Return the nearest known fee rate when a given conf target cannot be found * [Return the nearest known fee rate when a given conf target cannot be found
from Web API fee estimator.](https://github.com/lightningnetwork/lnd/pull/6062) from Web API fee estimator.](https://github.com/lightningnetwork/lnd/pull/6062)
* [We now _always_ set a channel type if the other party signals the feature
bit](https://github.com/lightningnetwork/lnd/pull/6075).
## Wallet ## Wallet
* A bug that prevented opening anchor-based channels from external wallets when * A bug that prevented opening anchor-based channels from external wallets when

View file

@ -26,8 +26,8 @@ var (
// will be attempted if the set of both local and remote features support it. // will be attempted if the set of both local and remote features support it.
// Otherwise, implicit negotiation will be attempted. // Otherwise, implicit negotiation will be attempted.
func negotiateCommitmentType(channelType *lnwire.ChannelType, func negotiateCommitmentType(channelType *lnwire.ChannelType,
local, remote *lnwire.FeatureVector, local, remote *lnwire.FeatureVector, mustBeExplicit bool,
mustBeExplicit bool) (bool, lnwallet.CommitmentType, error) { ) (bool, *lnwire.ChannelType, lnwallet.CommitmentType, error) {
if channelType != nil { if channelType != nil {
// If the peer does know explicit negotiation, let's attempt // If the peer does know explicit negotiation, let's attempt
@ -36,7 +36,7 @@ func negotiateCommitmentType(channelType *lnwire.ChannelType,
chanType, err := explicitNegotiateCommitmentType( chanType, err := explicitNegotiateCommitmentType(
*channelType, local, remote, *channelType, local, remote,
) )
return true, chanType, err return true, channelType, chanType, err
} }
// If we're the funder, and we are attempting to use an // If we're the funder, and we are attempting to use an
@ -45,11 +45,12 @@ func negotiateCommitmentType(channelType *lnwire.ChannelType,
// user doesn't end up with an unexpected channel type via // user doesn't end up with an unexpected channel type via
// implicit negotiation. // implicit negotiation.
if mustBeExplicit { if mustBeExplicit {
return false, 0, errUnsupportedExplicitNegotiation return false, nil, 0, errUnsupportedExplicitNegotiation
} }
} }
return false, implicitNegotiateCommitmentType(local, remote), nil chanType, commitType := implicitNegotiateCommitmentType(local, remote)
return false, chanType, commitType, nil
} }
// explicitNegotiateCommitmentType attempts to explicitly negotiate for a // explicitNegotiateCommitmentType attempts to explicitly negotiate for a
@ -113,12 +114,17 @@ func explicitNegotiateCommitmentType(channelType lnwire.ChannelType,
// implicitly by choosing the latest type supported by the local and remote // implicitly by choosing the latest type supported by the local and remote
// fetures. // fetures.
func implicitNegotiateCommitmentType(local, func implicitNegotiateCommitmentType(local,
remote *lnwire.FeatureVector) lnwallet.CommitmentType { remote *lnwire.FeatureVector) (*lnwire.ChannelType, lnwallet.CommitmentType) {
// If both peers are signalling support for anchor commitments with // If both peers are signalling support for anchor commitments with
// zero-fee HTLC transactions, we'll use this type. // zero-fee HTLC transactions, we'll use this type.
if hasFeatures(local, remote, lnwire.AnchorsZeroFeeHtlcTxOptional) { if hasFeatures(local, remote, lnwire.AnchorsZeroFeeHtlcTxOptional) {
return lnwallet.CommitmentTypeAnchorsZeroFeeHtlcTx chanType := lnwire.ChannelType(*lnwire.NewRawFeatureVector(
lnwire.AnchorsZeroFeeHtlcTxRequired,
lnwire.StaticRemoteKeyRequired,
))
return &chanType, lnwallet.CommitmentTypeAnchorsZeroFeeHtlcTx
} }
// Since we don't want to support the "legacy" anchor type, we will fall // Since we don't want to support the "legacy" anchor type, we will fall
@ -128,11 +134,16 @@ func implicitNegotiateCommitmentType(local,
// If both nodes are signaling the proper feature bit for tweakless // If both nodes are signaling the proper feature bit for tweakless
// commitments, we'll use that. // commitments, we'll use that.
if hasFeatures(local, remote, lnwire.StaticRemoteKeyOptional) { if hasFeatures(local, remote, lnwire.StaticRemoteKeyOptional) {
return lnwallet.CommitmentTypeTweakless chanType := lnwire.ChannelType(*lnwire.NewRawFeatureVector(
lnwire.StaticRemoteKeyRequired,
))
return &chanType, lnwallet.CommitmentTypeTweakless
} }
// Otherwise we'll fall back to the legacy type. // Otherwise we'll fall back to the legacy type.
return lnwallet.CommitmentTypeLegacy chanType := lnwire.ChannelType(*lnwire.NewRawFeatureVector())
return &chanType, lnwallet.CommitmentTypeLegacy
} }
// hasFeatures determines whether a set of features is supported by both the set // hasFeatures determines whether a set of features is supported by both the set

View file

@ -14,13 +14,14 @@ func TestCommitmentTypeNegotiation(t *testing.T) {
t.Parallel() t.Parallel()
testCases := []struct { testCases := []struct {
name string name string
mustBeExplicit bool mustBeExplicit bool
channelFeatures *lnwire.RawFeatureVector channelFeatures *lnwire.RawFeatureVector
localFeatures *lnwire.RawFeatureVector localFeatures *lnwire.RawFeatureVector
remoteFeatures *lnwire.RawFeatureVector remoteFeatures *lnwire.RawFeatureVector
expectsRes lnwallet.CommitmentType expectsCommitType lnwallet.CommitmentType
expectsErr error expectsChanType lnwire.ChannelType
expectsErr error
}{ }{
{ {
name: "explicit missing remote negotiation feature", name: "explicit missing remote negotiation feature",
@ -37,7 +38,11 @@ func TestCommitmentTypeNegotiation(t *testing.T) {
lnwire.StaticRemoteKeyOptional, lnwire.StaticRemoteKeyOptional,
lnwire.AnchorsZeroFeeHtlcTxOptional, lnwire.AnchorsZeroFeeHtlcTxOptional,
), ),
expectsRes: lnwallet.CommitmentTypeAnchorsZeroFeeHtlcTx, expectsCommitType: lnwallet.CommitmentTypeAnchorsZeroFeeHtlcTx,
expectsChanType: lnwire.ChannelType(*lnwire.NewRawFeatureVector(
lnwire.StaticRemoteKeyRequired,
lnwire.AnchorsZeroFeeHtlcTxRequired,
)),
expectsErr: nil, expectsErr: nil,
}, },
{ {
@ -92,7 +97,11 @@ func TestCommitmentTypeNegotiation(t *testing.T) {
lnwire.AnchorsZeroFeeHtlcTxOptional, lnwire.AnchorsZeroFeeHtlcTxOptional,
lnwire.ExplicitChannelTypeOptional, lnwire.ExplicitChannelTypeOptional,
), ),
expectsRes: lnwallet.CommitmentTypeAnchorsZeroFeeHtlcTx, expectsCommitType: lnwallet.CommitmentTypeAnchorsZeroFeeHtlcTx,
expectsChanType: lnwire.ChannelType(*lnwire.NewRawFeatureVector(
lnwire.StaticRemoteKeyRequired,
lnwire.AnchorsZeroFeeHtlcTxRequired,
)),
expectsErr: nil, expectsErr: nil,
}, },
{ {
@ -110,7 +119,10 @@ func TestCommitmentTypeNegotiation(t *testing.T) {
lnwire.AnchorsZeroFeeHtlcTxOptional, lnwire.AnchorsZeroFeeHtlcTxOptional,
lnwire.ExplicitChannelTypeOptional, lnwire.ExplicitChannelTypeOptional,
), ),
expectsRes: lnwallet.CommitmentTypeTweakless, expectsCommitType: lnwallet.CommitmentTypeTweakless,
expectsChanType: lnwire.ChannelType(*lnwire.NewRawFeatureVector(
lnwire.StaticRemoteKeyRequired,
)),
expectsErr: nil, expectsErr: nil,
}, },
{ {
@ -126,9 +138,13 @@ func TestCommitmentTypeNegotiation(t *testing.T) {
lnwire.AnchorsZeroFeeHtlcTxOptional, lnwire.AnchorsZeroFeeHtlcTxOptional,
lnwire.ExplicitChannelTypeOptional, lnwire.ExplicitChannelTypeOptional,
), ),
expectsRes: lnwallet.CommitmentTypeLegacy, expectsCommitType: lnwallet.CommitmentTypeLegacy,
expectsErr: nil, expectsChanType: lnwire.ChannelType(*lnwire.NewRawFeatureVector()),
expectsErr: nil,
}, },
// Both sides signal the explicit chan type bit, so we expect
// that we return the corresponding chan type feature bits,
// even though we didn't set an explicit channel type.
{ {
name: "implicit anchors", name: "implicit anchors",
channelFeatures: nil, channelFeatures: nil,
@ -142,7 +158,11 @@ func TestCommitmentTypeNegotiation(t *testing.T) {
lnwire.AnchorsZeroFeeHtlcTxOptional, lnwire.AnchorsZeroFeeHtlcTxOptional,
lnwire.ExplicitChannelTypeOptional, lnwire.ExplicitChannelTypeOptional,
), ),
expectsRes: lnwallet.CommitmentTypeAnchorsZeroFeeHtlcTx, expectsCommitType: lnwallet.CommitmentTypeAnchorsZeroFeeHtlcTx,
expectsChanType: lnwire.ChannelType(*lnwire.NewRawFeatureVector(
lnwire.StaticRemoteKeyRequired,
lnwire.AnchorsZeroFeeHtlcTxRequired,
)),
expectsErr: nil, expectsErr: nil,
}, },
{ {
@ -155,7 +175,10 @@ func TestCommitmentTypeNegotiation(t *testing.T) {
remoteFeatures: lnwire.NewRawFeatureVector( remoteFeatures: lnwire.NewRawFeatureVector(
lnwire.StaticRemoteKeyOptional, lnwire.StaticRemoteKeyOptional,
), ),
expectsRes: lnwallet.CommitmentTypeTweakless, expectsCommitType: lnwallet.CommitmentTypeTweakless,
expectsChanType: lnwire.ChannelType(*lnwire.NewRawFeatureVector(
lnwire.StaticRemoteKeyRequired,
)),
expectsErr: nil, expectsErr: nil,
}, },
{ {
@ -166,8 +189,9 @@ func TestCommitmentTypeNegotiation(t *testing.T) {
lnwire.StaticRemoteKeyOptional, lnwire.StaticRemoteKeyOptional,
lnwire.AnchorsZeroFeeHtlcTxOptional, lnwire.AnchorsZeroFeeHtlcTxOptional,
), ),
expectsRes: lnwallet.CommitmentTypeLegacy, expectsCommitType: lnwallet.CommitmentTypeLegacy,
expectsErr: nil, expectsChanType: lnwire.ChannelType(*lnwire.NewRawFeatureVector()),
expectsErr: nil,
}, },
} }
@ -188,13 +212,13 @@ func TestCommitmentTypeNegotiation(t *testing.T) {
*testCase.channelFeatures, *testCase.channelFeatures,
) )
} }
_, localType, err := negotiateCommitmentType( _, localChanType, localCommitType, err := negotiateCommitmentType(
channelType, localFeatures, remoteFeatures, channelType, localFeatures, remoteFeatures,
testCase.mustBeExplicit, testCase.mustBeExplicit,
) )
require.Equal(t, testCase.expectsErr, err) require.Equal(t, testCase.expectsErr, err)
_, remoteType, err := negotiateCommitmentType( _, remoteChanType, remoteCommitType, err := negotiateCommitmentType(
channelType, remoteFeatures, localFeatures, channelType, remoteFeatures, localFeatures,
testCase.mustBeExplicit, testCase.mustBeExplicit,
) )
@ -205,11 +229,20 @@ func TestCommitmentTypeNegotiation(t *testing.T) {
} }
require.Equal( require.Equal(
t, testCase.expectsRes, localType, t, testCase.expectsCommitType, localCommitType,
testCase.name, testCase.name,
) )
require.Equal( require.Equal(
t, testCase.expectsRes, remoteType, t, testCase.expectsCommitType, remoteCommitType,
testCase.name,
)
require.Equal(
t, testCase.expectsChanType, *localChanType,
testCase.name,
)
require.Equal(
t, testCase.expectsChanType, *remoteChanType,
testCase.name, testCase.name,
) )
}) })

View file

@ -1274,7 +1274,7 @@ func (f *Manager) handleFundingOpen(peer lnpeer.Peer,
// the remote peer are signaling the proper feature bit if we're using // the remote peer are signaling the proper feature bit if we're using
// implicit negotiation, and simply the channel type sent over if we're // implicit negotiation, and simply the channel type sent over if we're
// using explicit negotiation. // using explicit negotiation.
wasExplicit, commitType, err := negotiateCommitmentType( wasExplicit, _, commitType, err := negotiateCommitmentType(
msg.ChannelType, peer.LocalFeatures(), peer.RemoteFeatures(), msg.ChannelType, peer.LocalFeatures(), peer.RemoteFeatures(),
false, false,
) )
@ -1599,14 +1599,14 @@ func (f *Manager) handleFundingAccept(peer lnpeer.Peer,
// channel type in the accept_channel response if we didn't // channel type in the accept_channel response if we didn't
// explicitly set it in the open_channel message. For now, let's // explicitly set it in the open_channel message. For now, let's
// just log the problem instead of failing the funding flow. // just log the problem instead of failing the funding flow.
implicitChannelType := implicitNegotiateCommitmentType( _, implicitChannelType := implicitNegotiateCommitmentType(
peer.LocalFeatures(), peer.RemoteFeatures(), peer.LocalFeatures(), peer.RemoteFeatures(),
) )
// We pass in false here as the funder since at this point, we // We pass in false here as the funder since at this point, we
// didn't set a chan type ourselves, so falling back to // didn't set a chan type ourselves, so falling back to
// implicit funding is acceptable. // implicit funding is acceptable.
_, negotiatedChannelType, err := negotiateCommitmentType( _, _, negotiatedChannelType, err := negotiateCommitmentType(
msg.ChannelType, peer.LocalFeatures(), msg.ChannelType, peer.LocalFeatures(),
peer.RemoteFeatures(), false, peer.RemoteFeatures(), false,
) )
@ -3258,7 +3258,7 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) {
// Before we init the channel, we'll also check to see what commitment // Before we init the channel, we'll also check to see what commitment
// format we can use with this peer. This is dependent on *both* us and // format we can use with this peer. This is dependent on *both* us and
// the remote peer are signaling the proper feature bit. // the remote peer are signaling the proper feature bit.
_, commitType, err := negotiateCommitmentType( _, chanType, commitType, err := negotiateCommitmentType(
msg.ChannelType, msg.Peer.LocalFeatures(), msg.ChannelType, msg.Peer.LocalFeatures(),
msg.Peer.RemoteFeatures(), true, msg.Peer.RemoteFeatures(), true,
) )
@ -3415,7 +3415,7 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) {
FirstCommitmentPoint: ourContribution.FirstCommitmentPoint, FirstCommitmentPoint: ourContribution.FirstCommitmentPoint,
ChannelFlags: channelFlags, ChannelFlags: channelFlags,
UpfrontShutdownScript: shutdown, UpfrontShutdownScript: shutdown,
ChannelType: msg.ChannelType, ChannelType: chanType,
LeaseExpiry: leaseExpiry, LeaseExpiry: leaseExpiry,
} }
if err := msg.Peer.SendMessage(true, &fundingOpen); err != nil { if err := msg.Peer.SendMessage(true, &fundingOpen); err != nil {