Merge pull request #6027 from Roasbeef/funding-api-consistency

funding: ensure a local funding w/ explicit type can't be downgraded
This commit is contained in:
Olaoluwa Osuntokun authored and GitHub committed 2021-11-24 13:58:34 -08:00
commit 6c66338b14
4 files changed
+66 -11

No files matched your search

@@ -22,6 +22,10 @@
incompatibilities when opening channels with the latest versions of incompatibilities when opening channels with the latest versions of
c-lightning and eclair](https://github.com/lightningnetwork/lnd/pull/6026). c-lightning and eclair](https://github.com/lightningnetwork/lnd/pull/6026).
* [Ensure that if a user specifies explicit channel funding on the API level,
then it can't be
downgraded](https://github.com/lightningnetwork/lnd/pull/6027).
# Contributors (Alphabetical Order) # Contributors (Alphabetical Order)
* Jamie Turley * Jamie Turley
+20 -3
View File
@@ -8,6 +8,12 @@ import (
) )
var ( var (
// errUnsupportedExplicitNegotiation is an error returned when explicit
// channel commitment negotiation is attempted but either peer of the
// channel does not support it.
errUnsupportedExplicitNegotiation = errors.New("explicit channel " +
"type negotiation not supported")
// errUnsupportedCommitmentType is an error returned when a specific // errUnsupportedCommitmentType is an error returned when a specific
// channel commitment type is being explicitly negotiated but either // channel commitment type is being explicitly negotiated but either
// peer of the channel does not support it. // peer of the channel does not support it.
@@ -20,19 +26,30 @@ 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) (lnwallet.CommitmentType, error) { local, remote *lnwire.FeatureVector,
mustBeExplicit bool) (bool, 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
// that now. // that now.
if hasFeatures(local, remote, lnwire.ExplicitChannelTypeOptional) { if hasFeatures(local, remote, lnwire.ExplicitChannelTypeOptional) {
return explicitNegotiateCommitmentType( chanType, err := explicitNegotiateCommitmentType(
*channelType, local, remote, *channelType, local, remote,
) )
return true, chanType, err
}
// If we're the funder, and we are attempting to use an
// explicit channel type, but the remote party doesn't signal
// the bit, then we actually want to exit here, to ensure the
// user doesn't end up with an unexpected channel type via
// implicit negotiation.
if mustBeExplicit {
return false, 0, errUnsupportedExplicitNegotiation
} }
} }
return implicitNegotiateCommitmentType(local, remote), nil return false, implicitNegotiateCommitmentType(local, remote), nil
} }
// explicitNegotiateCommitmentType attempts to explicitly negotiate for a // explicitNegotiateCommitmentType attempts to explicitly negotiate for a
+24 -2
View File
@@ -15,6 +15,7 @@ func TestCommitmentTypeNegotiation(t *testing.T) {
testCases := []struct { testCases := []struct {
name string name string
mustBeExplicit bool
channelFeatures *lnwire.RawFeatureVector channelFeatures *lnwire.RawFeatureVector
localFeatures *lnwire.RawFeatureVector localFeatures *lnwire.RawFeatureVector
remoteFeatures *lnwire.RawFeatureVector remoteFeatures *lnwire.RawFeatureVector
@@ -39,6 +40,25 @@ func TestCommitmentTypeNegotiation(t *testing.T) {
expectsRes: lnwallet.CommitmentTypeAnchorsZeroFeeHtlcTx, expectsRes: lnwallet.CommitmentTypeAnchorsZeroFeeHtlcTx,
expectsErr: nil, expectsErr: nil,
}, },
{
name: "local funder wants explicit, remote doesn't " +
"support so fall back",
mustBeExplicit: true,
channelFeatures: lnwire.NewRawFeatureVector(
lnwire.StaticRemoteKeyRequired,
lnwire.AnchorsZeroFeeHtlcTxRequired,
),
localFeatures: lnwire.NewRawFeatureVector(
lnwire.StaticRemoteKeyOptional,
lnwire.AnchorsZeroFeeHtlcTxOptional,
lnwire.ExplicitChannelTypeOptional,
),
remoteFeatures: lnwire.NewRawFeatureVector(
lnwire.StaticRemoteKeyOptional,
lnwire.AnchorsZeroFeeHtlcTxOptional,
),
expectsErr: errUnsupportedExplicitNegotiation,
},
{ {
name: "explicit missing remote commitment feature", name: "explicit missing remote commitment feature",
channelFeatures: lnwire.NewRawFeatureVector( channelFeatures: lnwire.NewRawFeatureVector(
@@ -168,13 +188,15 @@ func TestCommitmentTypeNegotiation(t *testing.T) {
*testCase.channelFeatures, *testCase.channelFeatures,
) )
} }
localType, err := negotiateCommitmentType( _, localType, err := negotiateCommitmentType(
channelType, localFeatures, remoteFeatures, channelType, localFeatures, remoteFeatures,
testCase.mustBeExplicit,
) )
require.Equal(t, testCase.expectsErr, err) require.Equal(t, testCase.expectsErr, err)
remoteType, err := negotiateCommitmentType( _, remoteType, err := negotiateCommitmentType(
channelType, remoteFeatures, localFeatures, channelType, remoteFeatures, localFeatures,
testCase.mustBeExplicit,
) )
require.Equal(t, testCase.expectsErr, err) require.Equal(t, testCase.expectsErr, err)
+18 -6
View File
@@ -1274,8 +1274,9 @@ 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.
commitType, err := negotiateCommitmentType( wasExplicit, commitType, err := negotiateCommitmentType(
msg.ChannelType, peer.LocalFeatures(), peer.RemoteFeatures(), msg.ChannelType, peer.LocalFeatures(), peer.RemoteFeatures(),
false,
) )
if err != nil { if err != nil {
// TODO(roasbeef): should be using soft errors // TODO(roasbeef): should be using soft errors
@@ -1284,6 +1285,13 @@ func (f *Manager) handleFundingOpen(peer lnpeer.Peer,
return return
} }
// Only echo back a channel type in AcceptChannel if we actually used
// explicit negotiation above.
var chanTypeFeatureBits *lnwire.ChannelType
if wasExplicit {
chanTypeFeatureBits = msg.ChannelType
}
chainHash := chainhash.Hash(msg.ChainHash) chainHash := chainhash.Hash(msg.ChainHash)
req := &lnwallet.InitFundingReserveMsg{ req := &lnwallet.InitFundingReserveMsg{
ChainHash: &chainHash, ChainHash: &chainHash,
@@ -1520,7 +1528,7 @@ func (f *Manager) handleFundingOpen(peer lnpeer.Peer,
HtlcPoint: ourContribution.HtlcBasePoint.PubKey, HtlcPoint: ourContribution.HtlcBasePoint.PubKey,
FirstCommitmentPoint: ourContribution.FirstCommitmentPoint, FirstCommitmentPoint: ourContribution.FirstCommitmentPoint,
UpfrontShutdownScript: ourContribution.UpfrontShutdown, UpfrontShutdownScript: ourContribution.UpfrontShutdown,
ChannelType: msg.ChannelType, ChannelType: chanTypeFeatureBits,
LeaseExpiry: msg.LeaseExpiry, LeaseExpiry: msg.LeaseExpiry,
} }
@@ -1594,9 +1602,13 @@ func (f *Manager) handleFundingAccept(peer lnpeer.Peer,
implicitChannelType := implicitNegotiateCommitmentType( implicitChannelType := implicitNegotiateCommitmentType(
peer.LocalFeatures(), peer.RemoteFeatures(), peer.LocalFeatures(), peer.RemoteFeatures(),
) )
negotiatedChannelType, err := negotiateCommitmentType(
// We pass in false here as the funder since at this point, we
// didn't set a chan type ourselves, so falling back to
// implicit funding is acceptable.
_, negotiatedChannelType, err := negotiateCommitmentType(
msg.ChannelType, peer.LocalFeatures(), msg.ChannelType, peer.LocalFeatures(),
peer.RemoteFeatures(), peer.RemoteFeatures(), false,
) )
if err != nil { if err != nil {
err := errors.New("received unexpected channel type") err := errors.New("received unexpected channel type")
@@ -3246,9 +3258,9 @@ 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( _, commitType, err := negotiateCommitmentType(
msg.ChannelType, msg.Peer.LocalFeatures(), msg.ChannelType, msg.Peer.LocalFeatures(),
msg.Peer.RemoteFeatures(), msg.Peer.RemoteFeatures(), true,
) )
if err != nil { if err != nil {
log.Errorf("channel type negotiation failed: %v", err) log.Errorf("channel type negotiation failed: %v", err)