mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-01-19 05:45:21 +01:00
funding: use explicit commitment type negotiation when possible
In this commit, we modify the existing logic that defaults to implicit commitment type negotiation to support explicit negotiation if the new feature bit is set. This change allows us to ditch the notion of a "default" commitment type, as we'll now use feature bits to signal our understanding of a commiment type, but allow peers to select which commitment type they actually wish to use. In addition, this explicit negotiation removes the need for using the required bit of any commitment types. Instead, if an implementation wishes to no longer support a commitment type, they should simply stop advertising the optional bit.
This commit is contained in:
parent
e7885f2bde
commit
ad758d8499
@ -147,6 +147,10 @@ type reservationWithCtx struct {
|
||||
// maxLocalCsv is the maximum csv we will accept from the remote.
|
||||
maxLocalCsv uint16
|
||||
|
||||
// channelType is the explicit channel type proposed by the initiator of
|
||||
// the channel.
|
||||
channelType *lnwire.ChannelType
|
||||
|
||||
updateMtx sync.RWMutex
|
||||
lastUpdated time.Time
|
||||
|
||||
@ -1137,43 +1141,6 @@ 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.
|
||||
func commitmentType(localFeatures,
|
||||
remoteFeatures *lnwire.FeatureVector) lnwallet.CommitmentType {
|
||||
|
||||
// If both peers are signalling support for anchor commitments with
|
||||
// zero-fee HTLC transactions, we'll use this type.
|
||||
localZeroFee := localFeatures.HasFeature(
|
||||
lnwire.AnchorsZeroFeeHtlcTxOptional,
|
||||
)
|
||||
remoteZeroFee := remoteFeatures.HasFeature(
|
||||
lnwire.AnchorsZeroFeeHtlcTxOptional,
|
||||
)
|
||||
if localZeroFee && remoteZeroFee {
|
||||
return lnwallet.CommitmentTypeAnchorsZeroFeeHtlcTx
|
||||
}
|
||||
|
||||
// Since we don't want to support the "legacy" anchor type, we will
|
||||
// fall back to static remote key if the nodes don't support the zero
|
||||
// fee HTLC tx anchor type.
|
||||
localTweakless := localFeatures.HasFeature(
|
||||
lnwire.StaticRemoteKeyOptional,
|
||||
)
|
||||
remoteTweakless := remoteFeatures.HasFeature(
|
||||
lnwire.StaticRemoteKeyOptional,
|
||||
)
|
||||
|
||||
// If both nodes are signaling the proper feature bit for tweakless
|
||||
// copmmitments, we'll use that.
|
||||
if localTweakless && remoteTweakless {
|
||||
return lnwallet.CommitmentTypeTweakless
|
||||
}
|
||||
|
||||
// Otherwise we'll fall back to the legacy type.
|
||||
return lnwallet.CommitmentTypeLegacy
|
||||
}
|
||||
|
||||
// handleFundingOpen creates an initial 'ChannelReservation' within the wallet,
|
||||
// then responds to the source peer with an accept channel message progressing
|
||||
// the funding workflow.
|
||||
@ -1314,10 +1281,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 := negotiateCommitmentType(
|
||||
msg.ChannelType, peer.LocalFeatures(), peer.RemoteFeatures(),
|
||||
)
|
||||
if err != nil {
|
||||
// TODO(roasbeef): should be using soft errors
|
||||
log.Errorf("channel type negotiation failed: %v", err)
|
||||
f.failFundingFlow(peer, msg.PendingChannelID, err)
|
||||
return
|
||||
}
|
||||
|
||||
chainHash := chainhash.Hash(msg.ChainHash)
|
||||
req := &lnwallet.InitFundingReserveMsg{
|
||||
ChainHash: &chainHash,
|
||||
@ -1447,6 +1423,7 @@ func (f *Manager) handleFundingOpen(peer lnpeer.Peer,
|
||||
remoteMaxValue: remoteMaxValue,
|
||||
remoteMaxHtlcs: maxHtlcs,
|
||||
maxLocalCsv: f.cfg.MaxLocalCSVDelay,
|
||||
channelType: msg.ChannelType,
|
||||
err: make(chan error, 1),
|
||||
peer: peer,
|
||||
}
|
||||
@ -1519,6 +1496,7 @@ func (f *Manager) handleFundingOpen(peer lnpeer.Peer,
|
||||
HtlcPoint: ourContribution.HtlcBasePoint.PubKey,
|
||||
FirstCommitmentPoint: ourContribution.FirstCommitmentPoint,
|
||||
UpfrontShutdownScript: ourContribution.UpfrontShutdown,
|
||||
ChannelType: msg.ChannelType,
|
||||
}
|
||||
|
||||
if err := peer.SendMessage(true, &fundingAccept); err != nil {
|
||||
@ -1550,6 +1528,29 @@ func (f *Manager) handleFundingAccept(peer lnpeer.Peer,
|
||||
log.Infof("Recv'd fundingResponse for pending_id(%x)",
|
||||
pendingChanID[:])
|
||||
|
||||
// We'll want to quickly check that ChannelType echoed by the channel
|
||||
// request recipient matches what we proposed.
|
||||
//
|
||||
// TODO: Return errors as funding.Error to give context to remote peer?
|
||||
if resCtx.channelType != nil {
|
||||
if msg.ChannelType == nil {
|
||||
err := errors.New("explicit channel type not echoed back")
|
||||
f.failFundingFlow(peer, msg.PendingChannelID, err)
|
||||
return
|
||||
}
|
||||
proposedFeatures := lnwire.RawFeatureVector(*resCtx.channelType)
|
||||
ackedFeatures := lnwire.RawFeatureVector(*msg.ChannelType)
|
||||
if !proposedFeatures.Equals(&ackedFeatures) {
|
||||
err := errors.New("channel type mismatch")
|
||||
f.failFundingFlow(peer, msg.PendingChannelID, err)
|
||||
return
|
||||
}
|
||||
} else if msg.ChannelType != nil {
|
||||
err := errors.New("received unexpected channel type")
|
||||
f.failFundingFlow(peer, msg.PendingChannelID, err)
|
||||
return
|
||||
}
|
||||
|
||||
// The required number of confirmations should not be greater than the
|
||||
// maximum number of confirmations required by the ChainNotifier to
|
||||
// properly dispatch confirmations.
|
||||
@ -3183,9 +3184,15 @@ 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(
|
||||
msg.Peer.LocalFeatures(), msg.Peer.RemoteFeatures(),
|
||||
commitType, err := negotiateCommitmentType(
|
||||
msg.ChannelType, msg.Peer.LocalFeatures(),
|
||||
msg.Peer.RemoteFeatures(),
|
||||
)
|
||||
if err != nil {
|
||||
log.Errorf("channel type negotiation 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
|
||||
@ -3277,6 +3284,7 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) {
|
||||
remoteMaxValue: maxValue,
|
||||
remoteMaxHtlcs: maxHtlcs,
|
||||
maxLocalCsv: maxCSV,
|
||||
channelType: msg.ChannelType,
|
||||
reservation: reservation,
|
||||
peer: msg.Peer,
|
||||
updates: msg.Updates,
|
||||
@ -3320,6 +3328,7 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) {
|
||||
FirstCommitmentPoint: ourContribution.FirstCommitmentPoint,
|
||||
ChannelFlags: channelFlags,
|
||||
UpfrontShutdownScript: shutdown,
|
||||
ChannelType: msg.ChannelType,
|
||||
}
|
||||
if err := msg.Peer.SendMessage(true, &fundingOpen); err != nil {
|
||||
e := fmt.Errorf("unable to send funding request message: %v",
|
||||
|
Loading…
Reference in New Issue
Block a user