Skip to content
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