Skip to content

Commit

Permalink
htlcswitch/link: inspect sync errors, force close channel
Browse files Browse the repository at this point in the history
This commit makes the link inspect the error encountered during channel
sync, force closing the channel if we detect a remote data loss.
  • Loading branch information
halseth committed Jul 31, 2018
1 parent 410b730 commit ebed786
Showing 1 changed file with 65 additions and 10 deletions.
75 changes: 65 additions & 10 deletions htlcswitch/link.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
}
}
Expand Down

0 comments on commit ebed786

Please sign in to comment.