contractcourt/chain_watcher: add dispatchLocalForceClose

This commit adds a new method dispatchLocalClose, which will be called
in case our commitment is detected to spend the funding transaction. In
this case LocalUnilateralCloseInfo will be sent on the
LocalUnilateralClosure channel to all subscribers.

The UnilateralClosure channel is renamed to RemoteUnilateralClosure for
consistency.
This commit is contained in:
Johan T. Halseth 2018-03-16 14:08:37 +01:00
parent 7bacdd65dc
commit 49f4a70e5a
No known key found for this signature in database
GPG Key ID: 15BAADA29DA20D26

@ -16,6 +16,13 @@ import (
"github.com/roasbeef/btcutil"
)
// LocalUnilateralCloseInfo encapsulates all the informnation we need to act
// on a local force close that gets confirmed.
type LocalUnilateralCloseInfo struct {
*chainntnfs.SpendDetail
*lnwallet.LocalForceCloseSummary
}
// ChainEventSubscription is a struct that houses a subscription to be notified
// for any on-chain events related to a channel. There are three types of
// possible on-chain events: a cooperative channel closure, a unilateral
@ -25,13 +32,16 @@ type ChainEventSubscription struct {
// ChanPoint is that channel that chain events will be dispatched for.
ChanPoint wire.OutPoint
// UnilateralClosure is a channel that will be sent upon in the event that
// the remote party broadcasts their latest version of the commitment
// transaction.
UnilateralClosure chan *lnwallet.UnilateralCloseSummary
// RemoteUnilateralClosure is a channel that will be sent upon in the
// event that the remote party's commitment transaction is confirmed.
RemoteUnilateralClosure chan *lnwallet.UnilateralCloseSummary
// CooperativeClosure is a signal that will be sent upon once a cooperative
// channel closure has been detected.
// LocalUnilateralClosure is a channel that will be sent upon in the
// event that our commitment transaction is confirmed.
LocalUnilateralClosure chan *LocalUnilateralCloseInfo
// CooperativeClosure is a signal that will be sent upon once a
// cooperative channel closure has been detected confirmed.
//
// TODO(roasbeef): or something else
CooperativeClosure chan struct{}
@ -226,10 +236,11 @@ func (c *chainWatcher) SubscribeChannelEvents(syncDispatch bool) *ChainEventSubs
clientID, c.chanState.FundingOutpoint)
sub := &ChainEventSubscription{
ChanPoint: c.chanState.FundingOutpoint,
UnilateralClosure: make(chan *lnwallet.UnilateralCloseSummary, 1),
CooperativeClosure: make(chan struct{}, 1),
ContractBreach: make(chan *lnwallet.BreachRetribution, 1),
ChanPoint: c.chanState.FundingOutpoint,
RemoteUnilateralClosure: make(chan *lnwallet.UnilateralCloseSummary, 1),
LocalUnilateralClosure: make(chan *LocalUnilateralCloseInfo, 1),
CooperativeClosure: make(chan struct{}, 1),
ContractBreach: make(chan *lnwallet.BreachRetribution, 1),
Cancel: func() {
c.Lock()
delete(c.clientSubscriptions, clientID)
@ -307,6 +318,13 @@ func (c *chainWatcher) closeObserver(spendNtfn *chainntnfs.SpendEvent) {
&commitmentHash,
)
if isOurCommitment {
if err := c.dispatchLocalForceClose(
commitSpend, *localCommit,
); err != nil {
log.Errorf("unable to handle local"+
"close for chan_point=%v: %v",
c.chanState.FundingOutpoint, err)
}
return
}
@ -349,7 +367,7 @@ func (c *chainWatcher) closeObserver(spendNtfn *chainntnfs.SpendEvent) {
// has a fail crash _after_ accepting the new state,
// but _before_ sending their signature to us.
case broadcastStateNum >= remoteStateNum:
if err := c.dispatchRemoteClose(
if err := c.dispatchRemoteForceClose(
commitSpend, *remoteCommit,
); err != nil {
log.Errorf("unable to handle remote "+
@ -500,12 +518,45 @@ func (c *chainWatcher) dispatchCooperativeClose(commitSpend *chainntnfs.SpendDet
}
// dispatchRemoteClose processes a detected unilateral channel closure by the
// dispatchLocalForceClose processes a unilateral close by us being confirmed.
func (c *chainWatcher) dispatchLocalForceClose(
commitSpend *chainntnfs.SpendDetail,
localCommit channeldb.ChannelCommitment) error {
log.Infof("Local unilateral close of ChannelPoint(%v) "+
"detected", c.chanState.FundingOutpoint)
forceClose, err := lnwallet.NewLocalForceCloseSummary(
c.chanState, c.signer, c.pCache, commitSpend.SpendingTx,
localCommit,
)
if err != nil {
return err
}
// With the event processed, we'll now notify all subscribers of the
// event.
closeInfo := &LocalUnilateralCloseInfo{commitSpend, forceClose}
c.Lock()
for _, sub := range c.clientSubscriptions {
select {
case sub.LocalUnilateralClosure <- closeInfo:
case <-c.quit:
c.Unlock()
return fmt.Errorf("exiting")
}
}
c.Unlock()
return nil
}
// dispatchRemoteForceClose processes a detected unilateral channel closure by the
// remote party. This function will prepare a UnilateralCloseSummary which will
// then be sent to any subscribers allowing them to resolve all our funds in
// the channel on chain. Once this close summary is prepared, all registered
// subscribers will receive a notification of this event.
func (c *chainWatcher) dispatchRemoteClose(commitSpend *chainntnfs.SpendDetail,
func (c *chainWatcher) dispatchRemoteForceClose(commitSpend *chainntnfs.SpendDetail,
remoteCommit channeldb.ChannelCommitment) error {
log.Infof("Unilateral close of ChannelPoint(%v) "+
@ -538,7 +589,7 @@ func (c *chainWatcher) dispatchRemoteClose(commitSpend *chainntnfs.SpendDetail,
// * get ACK from the consumer of the ntfn before writing to disk?
// * no harm in repeated ntfns: at least once semantics
select {
case sub.UnilateralClosure <- uniClose:
case sub.RemoteUnilateralClosure <- uniClose:
case <-c.quit:
c.Unlock()
return fmt.Errorf("exiting")