From 2a77b57788b7350675d465b0071f962ee9d3d296 Mon Sep 17 00:00:00 2001 From: "Johan T. Halseth" Date: Thu, 26 Jul 2018 15:16:47 +0200 Subject: [PATCH] lnwallet + funding: move funding tx publish to fundingmgr This commit moves the responsibility for publishing the funding tx to the network from the wallet to the funding manager. This is done to distinguish the failure of completing the reservation within the wallet and failure of publishing the transaction. Earlier we could fail to broadcast the transaction, which would cause us to fail the funding flow. This is not something we can do directly, since the CompeteReservation call will mark the channel IsPending in the databas.e --- fundingmanager.go | 23 +++++++++++++++++++++-- lnwallet/reservation.go | 14 +++++++------- lnwallet/wallet.go | 24 +++++++----------------- 3 files changed, 35 insertions(+), 26 deletions(-) diff --git a/fundingmanager.go b/fundingmanager.go index 796fd885..c4410f53 100644 --- a/fundingmanager.go +++ b/fundingmanager.go @@ -1539,9 +1539,12 @@ func (f *fundingManager) handleFundingSigned(fmsg *fundingSignedMsg) { // transaction. We'll verify the signature for validity, then commit // the state to disk as we can now open the channel. commitSig := fmsg.msg.CommitSig.ToSignatureBytes() - completeChan, err := resCtx.reservation.CompleteReservation(nil, commitSig) + completeChan, err := resCtx.reservation.CompleteReservation( + nil, commitSig, + ) if err != nil { - fndgLog.Errorf("Unable to complete reservation sign complete: %v", err) + fndgLog.Errorf("Unable to complete reservation sign "+ + "complete: %v", err) f.failFundingFlow(fmsg.peer, pendingChanID, err) return } @@ -1550,6 +1553,22 @@ func (f *fundingManager) handleFundingSigned(fmsg *fundingSignedMsg) { // delete it from our set of active reservations. f.deleteReservationCtx(peerKey, pendingChanID) + // Broadcast the finalized funding transaction to the network. + fundingTx := completeChan.FundingTxn + fndgLog.Infof("Broadcasting funding tx for ChannelPoint(%v): %v", + completeChan.FundingOutpoint, spew.Sdump(fundingTx)) + + err = f.cfg.PublishTransaction(fundingTx) + if err != nil { + fndgLog.Errorf("unable to broadcast funding "+ + "txn: %v", err) + // We failed to broadcast the funding transaction, but watch + // the channel regardless, in case the transaction made it to + // the network. We will retry broadcast at startup. + // TODO(halseth): retry more often? Handle with CPFP? Just + // delete from the DB? + } + // Now that we have a finalized reservation for this funding flow, // we'll send the to be active channel to the ChainArbitrator so it can // watch for any on-chin actions before the channel has fully diff --git a/lnwallet/reservation.go b/lnwallet/reservation.go index f89945d6..30669344 100644 --- a/lnwallet/reservation.go +++ b/lnwallet/reservation.go @@ -4,12 +4,12 @@ import ( "net" "sync" - "github.com/lightningnetwork/lnd/channeldb" - "github.com/lightningnetwork/lnd/lnwire" "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcutil" + "github.com/lightningnetwork/lnd/channeldb" + "github.com/lightningnetwork/lnd/lnwire" ) // ChannelContribution is the primary constituent of the funding workflow @@ -434,11 +434,11 @@ func (r *ChannelReservation) OurSignatures() ([]*InputScript, []byte) { // https://github.com/bitcoin/bips/blob/master/bip-0069.mediawiki. // Additionally, verification is performed in order to ensure that the // counterparty supplied a valid signature to our version of the commitment -// transaction. Once this method returns, caller's should then call -// .WaitForChannelOpen() which will block until the funding transaction obtains -// the configured number of confirmations. Once the method unblocks, a -// LightningChannel instance is returned, marking the channel available for -// updates. +// transaction. Once this method returns, caller's should broadcast the +// created funding transaction, then call .WaitForChannelOpen() which will +// block until the funding transaction obtains the configured number of +// confirmations. Once the method unblocks, a LightningChannel instance is +// returned, marking the channel available for updates. func (r *ChannelReservation) CompleteReservation(fundingInputScripts []*InputScript, commitmentSig []byte) (*channeldb.OpenChannel, error) { diff --git a/lnwallet/wallet.go b/lnwallet/wallet.go index 0dcc4cc3..1e1bb934 100644 --- a/lnwallet/wallet.go +++ b/lnwallet/wallet.go @@ -8,20 +8,20 @@ import ( "sync" "sync/atomic" + "github.com/btcsuite/btcd/blockchain" + "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcutil/hdkeychain" "github.com/davecgh/go-spew/spew" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/lnwire" - "github.com/btcsuite/btcd/blockchain" - "github.com/btcsuite/btcd/chaincfg/chainhash" - "github.com/btcsuite/btcutil/hdkeychain" - "github.com/lightningnetwork/lnd/shachain" "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil/txsort" + "github.com/lightningnetwork/lnd/shachain" ) const ( @@ -262,15 +262,15 @@ type LightningWallet struct { // is removed from limbo. Each reservation is tracked by a unique // monotonically integer. All requests concerning the channel MUST // carry a valid, active funding ID. - fundingLimbo map[uint64]*ChannelReservation - limboMtx sync.RWMutex + fundingLimbo map[uint64]*ChannelReservation + limboMtx sync.RWMutex // lockedOutPoints is a set of the currently locked outpoint. This // information is kept in order to provide an easy way to unlock all // the currently locked outpoints. lockedOutPoints map[wire.OutPoint]struct{} - quit chan struct{} + quit chan struct{} wg sync.WaitGroup @@ -1086,16 +1086,6 @@ func (l *LightningWallet) handleFundingCounterPartySigs(msg *addCounterPartySigs return } - walletLog.Infof("Broadcasting funding tx for ChannelPoint(%v): %v", - res.partialState.FundingOutpoint, spew.Sdump(fundingTx)) - - // Broadcast the finalized funding transaction to the network. - if err := l.PublishTransaction(fundingTx); err != nil { - msg.err <- err - msg.completeChan <- nil - return - } - msg.completeChan <- res.partialState msg.err <- nil }