contractcourt: don't wait for DLP point if commit is tweakless on remote close

In this commit, we update the logic in the `chainWatcher` to no longer
wait until the DLP point has been populated in the database before we
dispatch the force close summary to any registered clients. Instead, we
can sweep immediately, as we have all the information we need to sweep
the funds (just our key).
This commit is contained in:
Olaoluwa Osuntokun 2019-07-31 20:22:55 -07:00
parent fdec603279
commit d22f2a1936
No known key found for this signature in database
GPG Key ID: BC13F65E2DC84465

@ -584,48 +584,32 @@ func (c *chainWatcher) closeObserver(spendNtfn *chainntnfs.SpendEvent) {
"state #%v!!! Attempting recovery...", "state #%v!!! Attempting recovery...",
broadcastStateNum, remoteStateNum) broadcastStateNum, remoteStateNum)
// If we are lucky, the remote peer sent us the correct tweaklessCommit := (c.cfg.chanState.ChanType ==
// commitment point during channel sync, such that we channeldb.SingleFunderTweakless)
// can sweep our funds. If we cannot find the commit
// point, there's not much we can do other than wait
// for us to retrieve it. We will attempt to retrieve
// it from the peer each time we connect to it.
//
// TODO(halseth): actively initiate re-connection to
// the peer?
var commitPoint *btcec.PublicKey
backoff := minCommitPointPollTimeout
for {
commitPoint, err = c.cfg.chanState.DataLossCommitPoint()
if err == nil {
break
}
log.Errorf("Unable to retrieve commitment "+ // If this isn't a tweakless commitment, then we'll
"point for channel(%v) with lost "+ // need to wait for the remote party's latest unrevoked
"state: %v. Retrying in %v.", // commitment point to be presented to us as we need
c.cfg.chanState.FundingOutpoint, // this to sweep. Otherwise, we can dispatch the remote
err, backoff) // close and sweep immediately using a fake commitPoint
// as it isn't actually needed for recovery anymore.
select { commitPoint := c.cfg.chanState.RemoteCurrentRevocation
// Wait before retrying, with an exponential if !tweaklessCommit {
// backoff. commitPoint = c.waitForCommitmentPoint()
case <-time.After(backoff): if commitPoint == nil {
backoff = 2 * backoff
if backoff > maxCommitPointPollTimeout {
backoff = maxCommitPointPollTimeout
}
case <-c.quit:
return return
} }
}
log.Infof("Recovered commit point(%x) for "+ log.Infof("Recovered commit point(%x) for "+
"channel(%v)! Now attempting to use it to "+ "channel(%v)! Now attempting to use it to "+
"sweep our funds...", "sweep our funds...",
commitPoint.SerializeCompressed(), commitPoint.SerializeCompressed(),
c.cfg.chanState.FundingOutpoint) c.cfg.chanState.FundingOutpoint)
} else {
log.Infof("ChannelPoint(%v) is tweakless, " +
"moving to sweep directly on chain")
}
// Since we don't have the commitment stored for this // Since we don't have the commitment stored for this
// state, we'll just pass an empty commitment within // state, we'll just pass an empty commitment within
@ -1009,3 +993,39 @@ func (c *chainWatcher) dispatchContractBreach(spendEvent *chainntnfs.SpendDetail
return nil return nil
} }
// waitForCommitmentPoint waits for the commitment point to be inserted into
// the local database. We'll use this method in the DLP case, to wait for the
// remote party to send us their point, as we can't proceed until we have that.
func (c *chainWatcher) waitForCommitmentPoint() *btcec.PublicKey {
// If we are lucky, the remote peer sent us the correct commitment
// point during channel sync, such that we can sweep our funds. If we
// cannot find the commit point, there's not much we can do other than
// wait for us to retrieve it. We will attempt to retrieve it from the
// peer each time we connect to it.
//
// TODO(halseth): actively initiate re-connection to the peer?
backoff := minCommitPointPollTimeout
for {
commitPoint, err := c.cfg.chanState.DataLossCommitPoint()
if err == nil {
return commitPoint
}
log.Errorf("Unable to retrieve commitment point for "+
"channel(%v) with lost state: %v. Retrying in %v.",
c.cfg.chanState.FundingOutpoint, err, backoff)
select {
// Wait before retrying, with an exponential backoff.
case <-time.After(backoff):
backoff = 2 * backoff
if backoff > maxCommitPointPollTimeout {
backoff = maxCommitPointPollTimeout
}
case <-c.quit:
return nil
}
}
}