funding: announce channel after confirmation, activate channel after FundingLocked

This commit modifies the order of operations after a channel has been
detected as fully opened. Rather than waiting until we receive the
FundingLocked message to announce the channel, we now do so immediately
after we detect the channel has been opened.

Additionally, we also patch a possible dead-lock bug by ensuring that
the RevokeAndAck message is always sent _after_ the FundingLocked
message. We do this by only passing the newly created channel too the
relevant sub-systems _after_ we receive the FundingLocked message. This
movement also serves to pave the way for our switch to the spec’s
funding workflow, as once we remove the initial revocation window,
there’ll be no way for us to initiate a state transition until we
receive the FundingLocked message from the remote party.
This commit is contained in:
Olaoluwa Osuntokun 2017-04-16 15:39:14 -07:00
parent 609cba95d7
commit 731f10eec0
No known key found for this signature in database
GPG Key ID: 9CC5B105D03521A2

@ -943,11 +943,82 @@ func (f *fundingManager) waitForFundingConfirmation(completeChan *channeldb.Open
return
}
// Now that the channel is open, we need to notify a number of parties
// of this event.
// Next, we'll send over the funding locked message which marks that we
// consider the channel open by presenting the remote party with our
// next revocation key. Without the revocation key, the remote party
// will be unable to propose state transitions.
nextRevocation, err := channel.NextRevocationkey()
if err != nil {
fndgLog.Errorf("unable to create next revocation: %v", err)
return
}
fundingLockedMsg := lnwire.NewFundingLocked(chanID, nextRevocation)
f.cfg.SendToPeer(completeChan.IdentityPub, fundingLockedMsg)
// First we send the newly opened channel to the source peer.
peer, err := f.cfg.FindPeer(completeChan.IdentityPub)
// With the block height and the transaction index known, we can
// construct the compact chanID which is used on the network to unique
// identify channels.
shortChanID := lnwire.ShortChannelID{
BlockHeight: confDetails.BlockHeight,
TxIndex: confDetails.TxIndex,
TxPosition: uint16(fundingPoint.Index),
}
fndgLog.Infof("Announcing ChannelPoint(%v), short_chan_id=%v", fundingPoint,
spew.Sdump(shortChanID))
// Register the new link with the L3 routing manager so this new
// channel can be utilized during path finding.
go f.announceChannel(f.cfg.IDKey, completeChan.IdentityPub,
channel.LocalFundingKey, channel.RemoteFundingKey,
shortChanID, chanID)
return
}
// processFundingLocked sends a message to the fundingManager allowing it to finish
// the funding workflow.
func (f *fundingManager) processFundingLocked(msg *lnwire.FundingLocked,
peerAddress *lnwire.NetAddress) {
f.fundingMsgs <- &fundingLockedMsg{msg, peerAddress}
}
// handleFundingLocked finalizes the channel funding process and enables the channel
// to enter normal operating mode.
func (f *fundingManager) handleFundingLocked(fmsg *fundingLockedMsg) {
// First, we'll attempt to locate the channel who's funding workflow is
// being finalized by this message. We got to the database rather than
// our reservation map as we may have restarted, mid funding flow.
chanID := fmsg.msg.ChanID
channel, err := f.cfg.FindChannel(chanID)
if err != nil {
fndgLog.Errorf("Unable to locate ChannelID(%v), cannot complete "+
"funding", chanID)
return
}
// With the channel retrieved, we'll send the breach arbiter the new
// channel so it can watch for attempts to breach the channel's
// contract by the remote
// party.
f.cfg.ArbiterChan <- channel
// Launch a defer so we _ensure_ that the channel barrier is properly
// closed even if the target peer is not longer online at this point.
defer func() {
// Close the active channel barrier signalling the readHandler
// that commitment related modifications to this channel can
// now proceed.
f.barrierMtx.Lock()
fndgLog.Tracef("Closing chan barrier for ChanID(%v)", chanID)
close(f.newChanBarriers[chanID])
delete(f.newChanBarriers, chanID)
f.barrierMtx.Unlock()
}()
// Finally, we'll find the peer that sent us this message so we can
// provide it with the fully initialized channel state.
peer, err := f.cfg.FindPeer(fmsg.peerAddress.IdentityKey)
if err != nil {
fndgLog.Errorf("Unable to find peer: %v", err)
return
@ -966,71 +1037,6 @@ func (f *fundingManager) waitForFundingConfirmation(completeChan *channeldb.Open
return
case <-newChanDone: // Fallthrough if we're not quitting.
}
// Close the active channel barrier signalling the readHandler that
// commitment related modifications to this channel can now proceed.
f.barrierMtx.Lock()
fndgLog.Tracef("Closing chan barrier for ChannelPoint(%v)", fundingPoint)
close(f.newChanBarriers[fundingPoint])
delete(f.newChanBarriers, fundingPoint)
f.barrierMtx.Unlock()
// Afterwards we send the breach arbiter the new channel so it can
// watch for attempts to breach the channel's contract by the remote
// party.
f.cfg.ArbiterChan <- channel
// With the block height and the transaction index known, we can
// construct the compact chainID which is used on the network to unique
// identify channels.
// TODO(roasbeef): remove after spec change, no more chanID's!!!
chanID := lnwire.ShortChannelID{
BlockHeight: confDetails.BlockHeight,
TxIndex: confDetails.TxIndex,
TxPosition: uint16(fundingPoint.Index),
}
// With the channel finally open, we'll now send over the funding
// locked message which marks that we consider the channel open by
// presenting the remote party with our next revocation key. Without
// the revocation key, the remote party will be unable to propose state
// transitions.
nextRevocation, err := channel.NextRevocationkey()
if err != nil {
fndgLog.Errorf("unable to create next revocation: %v", err)
return
}
fundingLockedMsg := lnwire.NewFundingLocked(fundingPoint, chanID,
nextRevocation)
f.cfg.SendToPeer(completeChan.IdentityPub, fundingLockedMsg)
return
}
// processFundingLocked sends a message to the fundingManager allowing it to finish
// the funding workflow.
func (f *fundingManager) processFundingLocked(msg *lnwire.FundingLocked,
peerAddress *lnwire.NetAddress) {
f.fundingMsgs <- &fundingLockedMsg{msg, peerAddress}
}
// handleFundingLocked finalizes the channel funding process and enables the channel
// to enter normal operating mode.
func (f *fundingManager) handleFundingLocked(fmsg *fundingLockedMsg) {
fundingPoint := fmsg.msg.ChannelOutpoint
channel, err := f.cfg.FindChannel(fundingPoint)
if err != nil {
fndgLog.Errorf("error looking up channel for outpoint: %v", fundingPoint)
return
}
// Register the new link with the L3 routing manager so this new
// channel can be utilized during path finding.
go f.announceChannel(f.cfg.IDKey, fmsg.peerAddress.IdentityKey,
channel.LocalFundingKey, channel.RemoteFundingKey,
fmsg.msg.ChannelID, fundingPoint)
}
// channelProof is one half of the proof necessary to create an authenticated