diff --git a/htlcswitch/link.go b/htlcswitch/link.go index 22de510e..d984dfb2 100644 --- a/htlcswitch/link.go +++ b/htlcswitch/link.go @@ -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 } }