fundingmanager: move final funding steps from wallet to funding manager.
Once a channel funding process has advanced to the point of broadcasting the funding transaction, the state of the channel should be persisted so that the nodes can disconnect or go down without having to wait for the funding transaction to be confirmed on the blockchain. Previously, the finalization of the funding process was handled by a combination of the funding manager, the peer and the wallet, but if the remote peer is no longer online or no longer connected, this flow will no longer work. This commit moves all funding steps following the transaction broadcast into the funding manager, which is available as long as the daemon is running.
This commit is contained in:
1 parent
508138f8c8
commit
e549a3f0ed
10 files changed
+402
-512
No files matched your search
+10
-131
@@ -1,7 +1,6 @@
|
||||
package lnwallet
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
@@ -185,6 +184,10 @@ type addCounterPartySigsMsg struct {
|
||||
// version of the commitment transaction.
|
||||
theirCommitmentSig []byte
|
||||
|
||||
// This channel is used to return the completed channel after the wallet
|
||||
// has completed all of its stages in the funding process.
|
||||
completeChan chan *channeldb.OpenChannel
|
||||
|
||||
// NOTE: In order to avoid deadlocks, this channel MUST be buffered.
|
||||
err chan error
|
||||
}
|
||||
@@ -215,19 +218,9 @@ type addSingleFunderSigsMsg struct {
|
||||
// the commitment transaction.
|
||||
obsfucator [StateHintSize]byte
|
||||
|
||||
// NOTE: In order to avoid deadlocks, this channel MUST be buffered.
|
||||
err chan error
|
||||
}
|
||||
|
||||
// channelOpenMsg is the final message sent to finalize a single funder channel
|
||||
// workflow to which we are the responder to. This message is sent once the
|
||||
// remote peer deems the channel open, meaning it has reached a sufficient
|
||||
// number of confirmations in the blockchain.
|
||||
type channelOpenMsg struct {
|
||||
pendingFundingID uint64
|
||||
|
||||
// TODO(roasbeef): move verification up to upper layer, yeh?
|
||||
spvProof []byte
|
||||
// This channel is used to return the completed channel after the wallet
|
||||
// has completed all of its stages in the funding process.
|
||||
completeChan chan *channeldb.OpenChannel
|
||||
|
||||
// NOTE: In order to avoid deadlocks, this channel MUST be buffered.
|
||||
err chan error
|
||||
@@ -461,8 +454,6 @@ out:
|
||||
l.handleSingleFunderSigs(msg)
|
||||
case *addCounterPartySigsMsg:
|
||||
l.handleFundingCounterPartySigs(msg)
|
||||
case *channelOpenMsg:
|
||||
l.handleChannelOpen(msg)
|
||||
}
|
||||
case <-l.quit:
|
||||
// TODO: do some clean up
|
||||
@@ -1072,10 +1063,7 @@ func (l *LightningWallet) handleFundingCounterPartySigs(msg *addCounterPartySigs
|
||||
return
|
||||
}
|
||||
|
||||
// Create a goroutine to watch the chain so we can open the channel once
|
||||
// the funding tx has enough confirmations.
|
||||
go l.openChannelAfterConfirmations(res)
|
||||
|
||||
msg.completeChan <- res.partialState
|
||||
msg.err <- nil
|
||||
}
|
||||
|
||||
@@ -1192,124 +1180,15 @@ func (l *LightningWallet) handleSingleFunderSigs(req *addSingleFunderSigsMsg) {
|
||||
}
|
||||
pendingReservation.ourCommitmentSig = sigTheirCommit
|
||||
|
||||
req.err <- nil
|
||||
}
|
||||
|
||||
// handleChannelOpen completes a single funder reservation to which we are the
|
||||
// responder. This method saves the channel state to disk, finally "opening"
|
||||
// the channel by sending it over to the caller of the reservation via the
|
||||
// channel dispatch channel.
|
||||
func (l *LightningWallet) handleChannelOpen(req *channelOpenMsg) {
|
||||
l.limboMtx.RLock()
|
||||
res, ok := l.fundingLimbo[req.pendingFundingID]
|
||||
l.limboMtx.RUnlock()
|
||||
if !ok {
|
||||
req.err <- fmt.Errorf("attempted to update non-existant " +
|
||||
"funding state")
|
||||
res.chanOpen <- nil
|
||||
return
|
||||
}
|
||||
|
||||
// Grab the mutex on the ChannelReservation to ensure thead-safety
|
||||
res.Lock()
|
||||
defer res.Unlock()
|
||||
|
||||
// Funding complete, this entry can be removed from limbo.
|
||||
l.limboMtx.Lock()
|
||||
delete(l.fundingLimbo, res.reservationID)
|
||||
l.limboMtx.Unlock()
|
||||
|
||||
// Add the complete funding transaction to the DB, in it's open bucket
|
||||
// which will be used for the lifetime of this channel.
|
||||
if err := res.partialState.SyncPending(res.nodeAddr); err != nil {
|
||||
if err := pendingReservation.partialState.SyncPending(pendingReservation.nodeAddr); err != nil {
|
||||
req.err <- err
|
||||
res.chanOpen <- nil
|
||||
return
|
||||
}
|
||||
|
||||
// Finally, create and officially open the payment channel!
|
||||
// TODO(roasbeef): CreationTime once tx is 'open'
|
||||
channel, err := NewLightningChannel(l.Signer, l.chainNotifier,
|
||||
res.partialState)
|
||||
if err != nil {
|
||||
req.err <- err
|
||||
res.chanOpen <- nil
|
||||
return
|
||||
}
|
||||
|
||||
req.completeChan <- pendingReservation.partialState
|
||||
req.err <- nil
|
||||
res.chanOpen <- &openChanDetails{
|
||||
channel: channel,
|
||||
}
|
||||
|
||||
// As this reservation has concluded, we can now safely remove the
|
||||
// reservation from the limbo map.
|
||||
l.limboMtx.Lock()
|
||||
delete(l.fundingLimbo, req.pendingFundingID)
|
||||
l.limboMtx.Unlock()
|
||||
}
|
||||
|
||||
// openChannelAfterConfirmations creates, and opens a payment channel after
|
||||
// the funding transaction created within the passed channel reservation
|
||||
// obtains the specified number of confirmations.
|
||||
func (l *LightningWallet) openChannelAfterConfirmations(res *ChannelReservation) {
|
||||
// Register with the ChainNotifier for a notification once the funding
|
||||
// transaction reaches `numConfs` confirmations.
|
||||
txid := res.fundingTx.TxHash()
|
||||
numConfs := uint32(res.numConfsToOpen)
|
||||
confNtfn, _ := l.chainNotifier.RegisterConfirmationsNtfn(&txid, numConfs)
|
||||
|
||||
walletLog.Infof("Waiting for funding tx (txid: %v) to reach %v confirmations",
|
||||
txid, numConfs)
|
||||
|
||||
// Wait until the specified number of confirmations has been reached,
|
||||
// or the wallet signals a shutdown.
|
||||
var (
|
||||
confDetails *chainntnfs.TxConfirmation
|
||||
ok bool
|
||||
)
|
||||
out:
|
||||
select {
|
||||
case confDetails, ok = <-confNtfn.Confirmed:
|
||||
// Reading a falsey value for the second parameter indicates that
|
||||
// the notifier is in the process of shutting down. Therefore, we
|
||||
// don't count this as the signal that the funding transaction has
|
||||
// been confirmed.
|
||||
if !ok {
|
||||
res.chanOpenErr <- errors.New("wallet shutting down")
|
||||
res.chanOpen <- nil
|
||||
return
|
||||
}
|
||||
|
||||
break out
|
||||
case <-l.quit:
|
||||
res.chanOpenErr <- errors.New("wallet shutting down")
|
||||
res.chanOpen <- nil
|
||||
return
|
||||
}
|
||||
|
||||
// Finally, create and officially open the payment channel!
|
||||
// TODO(roasbeef): CreationTime once tx is 'open'
|
||||
channel, err := NewLightningChannel(l.Signer, l.chainNotifier,
|
||||
res.partialState)
|
||||
if err != nil {
|
||||
res.chanOpenErr <- err
|
||||
res.chanOpen <- nil
|
||||
return
|
||||
}
|
||||
|
||||
res.chanOpenErr <- nil
|
||||
res.chanOpen <- &openChanDetails{
|
||||
channel: channel,
|
||||
blockHeight: confDetails.BlockHeight,
|
||||
txIndex: confDetails.TxIndex,
|
||||
}
|
||||
|
||||
// As this reservation has concluded, we can now safely remove the
|
||||
// reservation from the limbo map.
|
||||
l.limboMtx.Lock()
|
||||
delete(l.fundingLimbo, res.reservationID)
|
||||
l.limboMtx.Unlock()
|
||||
}
|
||||
|
||||
// selectCoinsAndChange performs coin selection in order to obtain witness
|
||||
|
||||
Reference in new issue
Block a user