htlcswitch/link: inspect sync errors, force close channel

This commit makes the link inspect the error encountered during channel
sync, force closing the channel if we detect a remote data loss.
This commit is contained in:
Johan T. Halseth 2018-07-12 11:02:54 +02:00
parent 410b730778
commit ebed786b2a
No known key found for this signature in database
GPG Key ID: 15BAADA29DA20D26

@ -613,10 +613,7 @@ func (l *channelLink) syncChanStates() error {
msgsToReSend, openedCircuits, closedCircuits, err =
l.channel.ProcessChanSyncMsg(remoteChanSyncMsg)
if err != nil {
// TODO(roasbeef): check concrete type of error, act
// accordingly
return fmt.Errorf("unable to handle upstream reestablish "+
"message: %v", err)
return err
}
// Repopulate any identifiers for circuits that may have been
@ -810,13 +807,71 @@ func (l *channelLink) htlcManager() {
if l.cfg.SyncStates {
err := l.syncChanStates()
if err != nil {
l.errorf("unable to synchronize channel states: %v", err)
if err != ErrLinkShuttingDown {
// TODO(halseth): must be revisted when
// data-loss protection is in.
l.fail(LinkFailureError{code: ErrSyncError},
err.Error())
switch {
case err == ErrLinkShuttingDown:
log.Debugf("unable to sync channel states, " +
"link is shutting down")
return
// We failed syncing the commit chains, probably
// because the remote has lost state. We should force
// close the channel.
// TODO(halseth): store sent chanSync message to
// database, such that it can be resent to peer in case
// it tries to sync the channel again.
case err == lnwallet.ErrCommitSyncRemoteDataLoss:
fallthrough
// The remote sent us an invalid last commit secret, we
// should force close the channel.
// TODO(halseth): and permanently ban the peer?
case err == lnwallet.ErrInvalidLastCommitSecret:
fallthrough
// The remote sent us a commit point different from
// what they sent us before.
// TODO(halseth): ban peer?
case err == lnwallet.ErrInvalidLocalUnrevokedCommitPoint:
l.fail(
LinkFailureError{
code: ErrSyncError,
ForceClose: true,
},
"unable to synchronize channel "+
"states: %v", err,
)
return
// We have lost state and cannot safely force close the
// channel. Fail the channel and wait for the remote to
// hopefully force close it. The remote has sent us its
// latest unrevoked commitment point, that we stored in
// the database, that we can use to retrieve the funds
// when the remote closes the channel.
// TODO(halseth): mark this, such that we prevent
// channel from being force closed by the user or
// contractcourt etc.
case err == lnwallet.ErrCommitSyncLocalDataLoss:
// We determined the commit chains were not possible to
// sync. We cautiously fail the channel, but don't
// force close.
// TODO(halseth): can we safely force close in any
// cases where this error is returned?
case err == lnwallet.ErrCannotSyncCommitChains:
// Other, unspecified error.
default:
}
l.fail(
LinkFailureError{
code: ErrSyncError,
ForceClose: false,
},
"unable to synchronize channel "+
"states: %v", err,
)
return
}
}