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

View File

@ -584,48 +584,32 @@ func (c *chainWatcher) closeObserver(spendNtfn *chainntnfs.SpendEvent) {
"state #%v!!! Attempting recovery...",
broadcastStateNum, remoteStateNum)
// 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?
var commitPoint *btcec.PublicKey
backoff := minCommitPointPollTimeout
for {
commitPoint, err = c.cfg.chanState.DataLossCommitPoint()
if err == nil {
break
}
tweaklessCommit := (c.cfg.chanState.ChanType ==
channeldb.SingleFunderTweakless)
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:
// If this isn't a tweakless commitment, then we'll
// need to wait for the remote party's latest unrevoked
// commitment point to be presented to us as we need
// this to sweep. Otherwise, we can dispatch the remote
// close and sweep immediately using a fake commitPoint
// as it isn't actually needed for recovery anymore.
commitPoint := c.cfg.chanState.RemoteCurrentRevocation
if !tweaklessCommit {
commitPoint = c.waitForCommitmentPoint()
if commitPoint == nil {
return
}
}
log.Infof("Recovered commit point(%x) for "+
"channel(%v)! Now attempting to use it to "+
"sweep our funds...",
commitPoint.SerializeCompressed(),
c.cfg.chanState.FundingOutpoint)
log.Infof("Recovered commit point(%x) for "+
"channel(%v)! Now attempting to use it to "+
"sweep our funds...",
commitPoint.SerializeCompressed(),
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
// state, we'll just pass an empty commitment within
@ -1009,3 +993,39 @@ func (c *chainWatcher) dispatchContractBreach(spendEvent *chainntnfs.SpendDetail
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
}
}
}