Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lnwire+funding: introduce new protocol extension for explicit channel type negotiation #5071

Closed
wants to merge 8 commits into from
2 changes: 2 additions & 0 deletions channeldb/channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,8 @@ const (
// fee negotiation, channel closing, the format of HTLCs, etc. Structure-wise,
// a ChannelType is a bit field, with each bit denoting a modification from the
// base channel type of single funder.
//
// TODO(roasbeef): do trick to roll this into a varint?
type ChannelType uint8

const (
Expand Down
4 changes: 4 additions & 0 deletions feature/default_sets.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,8 @@ var defaultSetDesc = setDesc{
SetInit: {}, // I
SetNodeAnn: {}, // N
},
lnwire.ExplicitChanTypeOptional: {
SetInit: {}, // I
SetNodeAnn: {}, // N
},
}
85 changes: 77 additions & 8 deletions funding/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,11 @@ type InitFundingMsg struct {
// protocol.
PendingChanID [32]byte

// ChanType allows the caller to use an explicit commitment type for
// the funding negotiation. This type will only be observed if BOTH
// sides support explicit channel negotiation.
ChanType lnwire.ChannelType

// Updates is a channel which updates to the opening status of the channel
// are sent on.
Updates chan *lnrpc.OpenStatusUpdate
Expand Down Expand Up @@ -1132,8 +1137,45 @@ func (f *Manager) ProcessFundingMsg(msg lnwire.Message, peer lnpeer.Peer) {

// commitmentType returns the commitment type to use for the channel, based on
// the features the two peers have available.
//
// TODO(roasbeef): afterwards no need to flip any required chan bits, simply
// remove the optional type if you don't want to use it any longer, allows
// deprecation of obsolete channel types
func commitmentType(localFeatures,
remoteFeatures *lnwire.FeatureVector) lnwallet.CommitmentType {
remoteFeatures *lnwire.FeatureVector,
explicitChanType lnwire.ChannelType) (lnwallet.CommitmentType, error) {

// First, we'll check if we're using explicit channel type negotiation.
explicitNegotiation := localFeatures.HasFeature(
lnwire.ExplicitChanTypeOptional,
) && remoteFeatures.HasFeature(
lnwire.ExplicitChanTypeOptional,
)

// If we are using explicit negotiation, then we'll simply attempt to
// map the wire level channel type to our internal commitment type.
// Along the way we'll also do proper validation to ensure they aren't
// proposing a channel type we don't support.
if explicitNegotiation {

switch explicitChanType {
case lnwire.ChanTypeBase:
return lnwallet.CommitmentTypeLegacy, nil

case lnwire.ChanTypeTweakless:
return lnwallet.CommitmentTypeTweakless, nil

case lnwire.ChanTypeZeroFeeAnchors:
return lnwallet.CommitmentTypeAnchorsZeroFeeHtlcTx, nil
default:
// TODO(roasbeef): add rejection if they send a feature
// type that we don't have a bit to, allows things to
// be properly deprecated

return 0, fmt.Errorf("unsupported channel type: %v",
explicitChanType)
}
}

// If both peers are signalling support for anchor commitments with
// zero-fee HTLC transactions, we'll use this type.
Expand All @@ -1144,7 +1186,7 @@ func commitmentType(localFeatures,
lnwire.AnchorsZeroFeeHtlcTxOptional,
)
if localZeroFee && remoteZeroFee {
return lnwallet.CommitmentTypeAnchorsZeroFeeHtlcTx
return lnwallet.CommitmentTypeAnchorsZeroFeeHtlcTx, nil
}

// Since we don't want to support the "legacy" anchor type, we will
Expand All @@ -1160,11 +1202,11 @@ func commitmentType(localFeatures,
// If both nodes are signaling the proper feature bit for tweakless
// copmmitments, we'll use that.
if localTweakless && remoteTweakless {
return lnwallet.CommitmentTypeTweakless
return lnwallet.CommitmentTypeTweakless, nil
}

// Otherwise we'll fall back to the legacy type.
return lnwallet.CommitmentTypeLegacy
return lnwallet.CommitmentTypeLegacy, nil
}

// handleFundingOpen creates an initial 'ChannelReservation' within the wallet,
Expand All @@ -1182,6 +1224,12 @@ func (f *Manager) handleFundingOpen(peer lnpeer.Peer,
peerPubKey := peer.IdentityKey()
peerIDKey := newSerializedKey(peerPubKey)

// TODO(roasbeef): reject if not amongst supported chan types
// * abstract away into ChanVersionNegotiator type interface?
// * new instance created at start, takes feature bits and set of
// allowed channel types
// * remove chan type setting from reservation?

amt := msg.FundingAmount

// We get all pending channels for this peer. This is the list of the
Expand Down Expand Up @@ -1307,10 +1355,19 @@ func (f *Manager) handleFundingOpen(peer lnpeer.Peer,
//
// 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
// the remote peer are signaling the proper feature bit.
commitType := commitmentType(
peer.LocalFeatures(), peer.RemoteFeatures(),
// 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
// using explicit negotiation.
commitType, err := commitmentType(
peer.LocalFeatures(), peer.RemoteFeatures(), msg.ChanType,
)
if err != nil {
// TODO(roasbeef): should be using soft errors
log.Errorf("channel type negotitation failed: %v", err)
f.failFundingFlow(peer, msg.PendingChannelID, err)
return
}

chainHash := chainhash.Hash(msg.ChainHash)
req := &lnwallet.InitFundingReserveMsg{
ChainHash: &chainHash,
Expand Down Expand Up @@ -1534,6 +1591,9 @@ func (f *Manager) handleFundingAccept(peer lnpeer.Peer,
return
}

// TODO(roasbeef): store reservation in chan type, send error if not
// expected

// Update the timestamp once the fundingAcceptMsg has been handled.
defer resCtx.updateTimestamp()

Expand Down Expand Up @@ -3172,9 +3232,18 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) {
// 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
// the remote peer are signaling the proper feature bit.
commitType := commitmentType(
//
// TODO(roasbeef): pass in arg to make commit type optional via pointer
// variable?
commitType, err := commitmentType(
msg.Peer.LocalFeatures(), msg.Peer.RemoteFeatures(),
msg.ChanType,
)
if err != nil {
log.Errorf("channel type negotitation failed: %v", err)
msg.Err <- err
return
}

// First, we'll query the fee estimator for a fee that should get the
// commitment transaction confirmed by the next few blocks (conf target
Expand Down
Loading