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" "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 // 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 // for any on-chain events related to a channel. There are three types of
// possible on-chain events: a cooperative channel closure, a unilateral // 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 is that channel that chain events will be dispatched for.
ChanPoint wire.OutPoint ChanPoint wire.OutPoint
// UnilateralClosure is a channel that will be sent upon in the event that // RemoteUnilateralClosure is a channel that will be sent upon in the
// the remote party broadcasts their latest version of the commitment // event that the remote party's commitment transaction is confirmed.
// transaction. RemoteUnilateralClosure chan *lnwallet.UnilateralCloseSummary
UnilateralClosure chan *lnwallet.UnilateralCloseSummary
// CooperativeClosure is a signal that will be sent upon once a cooperative // LocalUnilateralClosure is a channel that will be sent upon in the
// channel closure has been detected. // 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 // TODO(roasbeef): or something else
CooperativeClosure chan struct{} CooperativeClosure chan struct{}
@ -226,10 +236,11 @@ func (c *chainWatcher) SubscribeChannelEvents(syncDispatch bool) *ChainEventSubs
clientID, c.chanState.FundingOutpoint) clientID, c.chanState.FundingOutpoint)
sub := &ChainEventSubscription{ sub := &ChainEventSubscription{
ChanPoint: c.chanState.FundingOutpoint, ChanPoint: c.chanState.FundingOutpoint,
UnilateralClosure: make(chan *lnwallet.UnilateralCloseSummary, 1), RemoteUnilateralClosure: make(chan *lnwallet.UnilateralCloseSummary, 1),
CooperativeClosure: make(chan struct{}, 1), LocalUnilateralClosure: make(chan *LocalUnilateralCloseInfo, 1),
ContractBreach: make(chan *lnwallet.BreachRetribution, 1), CooperativeClosure: make(chan struct{}, 1),
ContractBreach: make(chan *lnwallet.BreachRetribution, 1),
Cancel: func() { Cancel: func() {
c.Lock() c.Lock()
delete(c.clientSubscriptions, clientID) delete(c.clientSubscriptions, clientID)
@ -307,6 +318,13 @@ func (c *chainWatcher) closeObserver(spendNtfn *chainntnfs.SpendEvent) {
&commitmentHash, &commitmentHash,
) )
if isOurCommitment { 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 return
} }
@ -349,7 +367,7 @@ func (c *chainWatcher) closeObserver(spendNtfn *chainntnfs.SpendEvent) {
// has a fail crash _after_ accepting the new state, // has a fail crash _after_ accepting the new state,
// but _before_ sending their signature to us. // but _before_ sending their signature to us.
case broadcastStateNum >= remoteStateNum: case broadcastStateNum >= remoteStateNum:
if err := c.dispatchRemoteClose( if err := c.dispatchRemoteForceClose(
commitSpend, *remoteCommit, commitSpend, *remoteCommit,
); err != nil { ); err != nil {
log.Errorf("unable to handle remote "+ 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 // remote party. This function will prepare a UnilateralCloseSummary which will
// then be sent to any subscribers allowing them to resolve all our funds in // 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 // the channel on chain. Once this close summary is prepared, all registered
// subscribers will receive a notification of this event. // 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 { remoteCommit channeldb.ChannelCommitment) error {
log.Infof("Unilateral close of ChannelPoint(%v) "+ 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? // * get ACK from the consumer of the ntfn before writing to disk?
// * no harm in repeated ntfns: at least once semantics // * no harm in repeated ntfns: at least once semantics
select { select {
case sub.UnilateralClosure <- uniClose: case sub.RemoteUnilateralClosure <- uniClose:
case <-c.quit: case <-c.quit:
c.Unlock() c.Unlock()
return fmt.Errorf("exiting") return fmt.Errorf("exiting")