diff --git a/contractcourt/chain_watcher.go b/contractcourt/chain_watcher.go index 606ce980..2163ee92 100644 --- a/contractcourt/chain_watcher.go +++ b/contractcourt/chain_watcher.go @@ -10,7 +10,6 @@ import ( "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/lnwallet" "github.com/roasbeef/btcd/chaincfg" - "github.com/roasbeef/btcd/chaincfg/chainhash" "github.com/roasbeef/btcd/txscript" "github.com/roasbeef/btcd/wire" "github.com/roasbeef/btcutil" @@ -123,12 +122,6 @@ type chainWatcher struct { // clientSubscriptions is a map that keeps track of all the active // client subscriptions for events related to this channel. clientSubscriptions map[uint64]*ChainEventSubscription - - // possibleCloses is a map from cooperative closing transaction txid to - // a close summary that describes the nature of the channel closure. - // We'll use this map to keep track of all possible channel closures to - // ensure out db state is correct in the end. - possibleCloses map[chainhash.Hash]*channeldb.ChannelCloseSummary } // newChainWatcher returns a new instance of a chainWatcher for a channel given @@ -158,7 +151,6 @@ func newChainWatcher(cfg chainWatcherConfig) (*chainWatcher, error) { stateHintObfuscator: stateHint, quit: make(chan struct{}), clientSubscriptions: make(map[uint64]*ChainEventSubscription), - possibleCloses: make(map[chainhash.Hash]*channeldb.ChannelCloseSummary), }, nil } @@ -751,147 +743,3 @@ func (c *chainWatcher) dispatchContractBreach(spendEvent *chainntnfs.SpendDetail return nil } - -// CooperativeCloseCtx is a transactional object that's used by external -// parties to initiate a cooperative closure negotiation. During the -// negotiation, we sign multiple versions of a closing transaction, either of -// which may be counter signed and broadcast by the remote party at any time. -// As a result, we'll need to watch the chain to see if any of these confirm, -// only afterwards will we mark the channel as fully closed. -type CooperativeCloseCtx struct { - // potentialCloses is a channel will be used by the party negotiating - // the cooperative closure to send possible closing states to the chain - // watcher to ensure we detect all on-chain spends. - potentialCloses chan *channeldb.ChannelCloseSummary - - // activeCloses keeps track of all the txid's that we're currently - // watching for. - activeCloses map[chainhash.Hash]struct{} - - // watchCancel will be closed once *one* of the txid's in the map above - // is confirmed. This will cause all the lingering goroutines to exit. - watchCancel chan struct{} - - watcher *chainWatcher - - sync.Mutex -} - -// BeginCooperativeClose should be called by the party negotiating the -// cooperative closure before the first signature is sent to the remote party. -// This will return a context that should be used to communicate possible -// closing states so we can act on them. -func (c *chainWatcher) BeginCooperativeClose() *CooperativeCloseCtx { - // We'll simply return a new close context that will be used be the - // caller to notify us of potential closes. - return &CooperativeCloseCtx{ - potentialCloses: make(chan *channeldb.ChannelCloseSummary), - watchCancel: make(chan struct{}), - activeCloses: make(map[chainhash.Hash]struct{}), - watcher: c, - } -} - -// LogPotentialClose should be called by the party negotiating the cooperative -// closure once they signed a new state, but *before* they transmit it to the -// remote party. This will ensure that the chain watcher is able to log the new -// state it should watch the chain for. -func (c *CooperativeCloseCtx) LogPotentialClose(potentialClose *channeldb.ChannelCloseSummary) { - c.Lock() - defer c.Unlock() - - // We'll check to see if we're already watching for a close of this - // channel, if so, then we'll exit early to avoid launching a duplicate - // goroutine. - if _, ok := c.activeCloses[potentialClose.ClosingTXID]; ok { - return - } - - // Otherwise, we'll mark this txid as currently being watched. - c.activeCloses[potentialClose.ClosingTXID] = struct{}{} - - // We'll take this potential close, and launch a goroutine which will - // wait until it's confirmed, then update the database state. When a - // potential close gets confirmed, we'll cancel out all other launched - // goroutines. - go func() { - confNtfn, err := c.watcher.cfg.notifier.RegisterConfirmationsNtfn( - &potentialClose.ClosingTXID, 1, - uint32(potentialClose.CloseHeight), - ) - if err != nil { - log.Errorf("unable to register for conf: %v", err) - return - } - - log.Infof("closeCtx: waiting for txid=%v to close "+ - "ChannelPoint(%v) on chain", potentialClose.ClosingTXID, - c.watcher.cfg.chanState.FundingOutpoint) - - select { - case confInfo, ok := <-confNtfn.Confirmed: - if !ok { - log.Errorf("notifier exiting") - return - } - - log.Infof("closeCtx: ChannelPoint(%v) is fully closed, at "+ - "height: %v", c.watcher.cfg.chanState.FundingOutpoint, - confInfo.BlockHeight) - - close(c.watchCancel) - - c.watcher.Lock() - for _, sub := range c.watcher.clientSubscriptions { - select { - case sub.CooperativeClosure <- struct{}{}: - case <-c.watcher.quit: - } - } - c.watcher.Unlock() - - err := c.watcher.cfg.chanState.CloseChannel(potentialClose) - if err != nil { - log.Warnf("closeCtx: unable to update latest "+ - "close for ChannelPoint(%v): %v", - c.watcher.cfg.chanState.FundingOutpoint, err) - } - - err = c.watcher.cfg.markChanClosed() - if err != nil { - log.Errorf("closeCtx: unable to mark chan fully "+ - "closed: %v", err) - return - } - - case <-c.watchCancel: - log.Debugf("Exiting watch for close of txid=%v for "+ - "ChannelPoint(%v)", potentialClose.ClosingTXID, - c.watcher.cfg.chanState.FundingOutpoint) - - case <-c.watcher.quit: - return - } - }() -} - -// Finalize should be called once both parties agree on a final transaction to -// close out the channel. This method will immediately mark the channel as -// pending closed in the database, then launch a goroutine to mark the channel -// fully closed upon confirmation. -func (c *CooperativeCloseCtx) Finalize(preferredClose *channeldb.ChannelCloseSummary) error { - chanPoint := c.watcher.cfg.chanState.FundingOutpoint - - log.Infof("Finalizing chan close for ChannelPoint(%v)", chanPoint) - - err := c.watcher.cfg.chanState.CloseChannel(preferredClose) - if err != nil { - log.Errorf("closeCtx: unable to close ChannelPoint(%v): %v", - chanPoint, err) - return err - } - - go c.LogPotentialClose(preferredClose) - - return nil -}