Skip to content

Commit 6c66338

Browse files
authored
Merge pull request #6027 from Roasbeef/funding-api-consistency
funding: ensure a local funding w/ explicit type can't be downgraded
2 parents 53342b4 + ed854cf commit 6c66338

File tree

4 files changed

+66
-11
lines changed

4 files changed

+66
-11
lines changed

docs/release-notes/release-notes-0.14.1.md

+4
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@
2222
incompatibilities when opening channels with the latest versions of
2323
c-lightning and eclair](https://github.com/lightningnetwork/lnd/pull/6026).
2424

25+
* [Ensure that if a user specifies explicit channel funding on the API level,
26+
then it can't be
27+
downgraded](https://github.com/lightningnetwork/lnd/pull/6027).
28+
2529
# Contributors (Alphabetical Order)
2630

2731
* Jamie Turley

funding/commitment_type_negotiation.go

+20-3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ import (
88
)
99

1010
var (
11+
// errUnsupportedExplicitNegotiation is an error returned when explicit
12+
// channel commitment negotiation is attempted but either peer of the
13+
// channel does not support it.
14+
errUnsupportedExplicitNegotiation = errors.New("explicit channel " +
15+
"type negotiation not supported")
16+
1117
// errUnsupportedCommitmentType is an error returned when a specific
1218
// channel commitment type is being explicitly negotiated but either
1319
// peer of the channel does not support it.
@@ -20,19 +26,30 @@ var (
2026
// will be attempted if the set of both local and remote features support it.
2127
// Otherwise, implicit negotiation will be attempted.
2228
func negotiateCommitmentType(channelType *lnwire.ChannelType,
23-
local, remote *lnwire.FeatureVector) (lnwallet.CommitmentType, error) {
29+
local, remote *lnwire.FeatureVector,
30+
mustBeExplicit bool) (bool, lnwallet.CommitmentType, error) {
2431

2532
if channelType != nil {
2633
// If the peer does know explicit negotiation, let's attempt
2734
// that now.
2835
if hasFeatures(local, remote, lnwire.ExplicitChannelTypeOptional) {
29-
return explicitNegotiateCommitmentType(
36+
chanType, err := explicitNegotiateCommitmentType(
3037
*channelType, local, remote,
3138
)
39+
return true, chanType, err
40+
}
41+
42+
// If we're the funder, and we are attempting to use an
43+
// explicit channel type, but the remote party doesn't signal
44+
// the bit, then we actually want to exit here, to ensure the
45+
// user doesn't end up with an unexpected channel type via
46+
// implicit negotiation.
47+
if mustBeExplicit {
48+
return false, 0, errUnsupportedExplicitNegotiation
3249
}
3350
}
3451

35-
return implicitNegotiateCommitmentType(local, remote), nil
52+
return false, implicitNegotiateCommitmentType(local, remote), nil
3653
}
3754

3855
// explicitNegotiateCommitmentType attempts to explicitly negotiate for a

funding/commitment_type_negotiation_test.go

+24-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ func TestCommitmentTypeNegotiation(t *testing.T) {
1515

1616
testCases := []struct {
1717
name string
18+
mustBeExplicit bool
1819
channelFeatures *lnwire.RawFeatureVector
1920
localFeatures *lnwire.RawFeatureVector
2021
remoteFeatures *lnwire.RawFeatureVector
@@ -39,6 +40,25 @@ func TestCommitmentTypeNegotiation(t *testing.T) {
3940
expectsRes: lnwallet.CommitmentTypeAnchorsZeroFeeHtlcTx,
4041
expectsErr: nil,
4142
},
43+
{
44+
name: "local funder wants explicit, remote doesn't " +
45+
"support so fall back",
46+
mustBeExplicit: true,
47+
channelFeatures: lnwire.NewRawFeatureVector(
48+
lnwire.StaticRemoteKeyRequired,
49+
lnwire.AnchorsZeroFeeHtlcTxRequired,
50+
),
51+
localFeatures: lnwire.NewRawFeatureVector(
52+
lnwire.StaticRemoteKeyOptional,
53+
lnwire.AnchorsZeroFeeHtlcTxOptional,
54+
lnwire.ExplicitChannelTypeOptional,
55+
),
56+
remoteFeatures: lnwire.NewRawFeatureVector(
57+
lnwire.StaticRemoteKeyOptional,
58+
lnwire.AnchorsZeroFeeHtlcTxOptional,
59+
),
60+
expectsErr: errUnsupportedExplicitNegotiation,
61+
},
4262
{
4363
name: "explicit missing remote commitment feature",
4464
channelFeatures: lnwire.NewRawFeatureVector(
@@ -168,13 +188,15 @@ func TestCommitmentTypeNegotiation(t *testing.T) {
168188
*testCase.channelFeatures,
169189
)
170190
}
171-
localType, err := negotiateCommitmentType(
191+
_, localType, err := negotiateCommitmentType(
172192
channelType, localFeatures, remoteFeatures,
193+
testCase.mustBeExplicit,
173194
)
174195
require.Equal(t, testCase.expectsErr, err)
175196

176-
remoteType, err := negotiateCommitmentType(
197+
_, remoteType, err := negotiateCommitmentType(
177198
channelType, remoteFeatures, localFeatures,
199+
testCase.mustBeExplicit,
178200
)
179201
require.Equal(t, testCase.expectsErr, err)
180202

funding/manager.go

+18-6
Original file line numberDiff line numberDiff line change
@@ -1274,8 +1274,9 @@ func (f *Manager) handleFundingOpen(peer lnpeer.Peer,
12741274
// the remote peer are signaling the proper feature bit if we're using
12751275
// implicit negotiation, and simply the channel type sent over if we're
12761276
// using explicit negotiation.
1277-
commitType, err := negotiateCommitmentType(
1277+
wasExplicit, commitType, err := negotiateCommitmentType(
12781278
msg.ChannelType, peer.LocalFeatures(), peer.RemoteFeatures(),
1279+
false,
12791280
)
12801281
if err != nil {
12811282
// TODO(roasbeef): should be using soft errors
@@ -1284,6 +1285,13 @@ func (f *Manager) handleFundingOpen(peer lnpeer.Peer,
12841285
return
12851286
}
12861287

1288+
// Only echo back a channel type in AcceptChannel if we actually used
1289+
// explicit negotiation above.
1290+
var chanTypeFeatureBits *lnwire.ChannelType
1291+
if wasExplicit {
1292+
chanTypeFeatureBits = msg.ChannelType
1293+
}
1294+
12871295
chainHash := chainhash.Hash(msg.ChainHash)
12881296
req := &lnwallet.InitFundingReserveMsg{
12891297
ChainHash: &chainHash,
@@ -1520,7 +1528,7 @@ func (f *Manager) handleFundingOpen(peer lnpeer.Peer,
15201528
HtlcPoint: ourContribution.HtlcBasePoint.PubKey,
15211529
FirstCommitmentPoint: ourContribution.FirstCommitmentPoint,
15221530
UpfrontShutdownScript: ourContribution.UpfrontShutdown,
1523-
ChannelType: msg.ChannelType,
1531+
ChannelType: chanTypeFeatureBits,
15241532
LeaseExpiry: msg.LeaseExpiry,
15251533
}
15261534

@@ -1594,9 +1602,13 @@ func (f *Manager) handleFundingAccept(peer lnpeer.Peer,
15941602
implicitChannelType := implicitNegotiateCommitmentType(
15951603
peer.LocalFeatures(), peer.RemoteFeatures(),
15961604
)
1597-
negotiatedChannelType, err := negotiateCommitmentType(
1605+
1606+
// We pass in false here as the funder since at this point, we
1607+
// didn't set a chan type ourselves, so falling back to
1608+
// implicit funding is acceptable.
1609+
_, negotiatedChannelType, err := negotiateCommitmentType(
15981610
msg.ChannelType, peer.LocalFeatures(),
1599-
peer.RemoteFeatures(),
1611+
peer.RemoteFeatures(), false,
16001612
)
16011613
if err != nil {
16021614
err := errors.New("received unexpected channel type")
@@ -3246,9 +3258,9 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) {
32463258
// Before we init the channel, we'll also check to see what commitment
32473259
// format we can use with this peer. This is dependent on *both* us and
32483260
// the remote peer are signaling the proper feature bit.
3249-
commitType, err := negotiateCommitmentType(
3261+
_, commitType, err := negotiateCommitmentType(
32503262
msg.ChannelType, msg.Peer.LocalFeatures(),
3251-
msg.Peer.RemoteFeatures(),
3263+
msg.Peer.RemoteFeatures(), true,
32523264
)
32533265
if err != nil {
32543266
log.Errorf("channel type negotiation failed: %v", err)

0 commit comments

Comments
 (0)