lnwallet/channel: make ErrCommitSyncLocalDataLoss type

This commit converts the ErrCommitSyncLocalDataLoss error into a struct,
that also holds the received last unrevoked commit point from the remote
party.
This commit is contained in:
Johan T. Halseth 2019-09-06 13:14:39 +02:00
parent d75feeb953
commit f40f4620f7
No known key found for this signature in database
GPG Key ID: 15BAADA29DA20D26
3 changed files with 37 additions and 14 deletions

@ -895,6 +895,11 @@ func (l *channelLink) htlcManager() {
if l.cfg.SyncStates { if l.cfg.SyncStates {
err := l.syncChanStates() err := l.syncChanStates()
if err != nil { if err != nil {
log.Warnf("Error when syncing channel states: %v", err)
_, localDataLoss :=
err.(*lnwallet.ErrCommitSyncLocalDataLoss)
switch { switch {
case err == ErrLinkShuttingDown: case err == ErrLinkShuttingDown:
log.Debugf("unable to sync channel states, " + log.Debugf("unable to sync channel states, " +
@ -936,7 +941,7 @@ func (l *channelLink) htlcManager() {
// TODO(halseth): mark this, such that we prevent // TODO(halseth): mark this, such that we prevent
// channel from being force closed by the user or // channel from being force closed by the user or
// contractcourt etc. // contractcourt etc.
case err == lnwallet.ErrCommitSyncLocalDataLoss: case localDataLoss:
// We determined the commit chains were not possible to // We determined the commit chains were not possible to
// sync. We cautiously fail the channel, but don't // sync. We cautiously fail the channel, but don't

@ -81,16 +81,6 @@ var (
ErrInvalidLocalUnrevokedCommitPoint = fmt.Errorf("unrevoked commit " + ErrInvalidLocalUnrevokedCommitPoint = fmt.Errorf("unrevoked commit " +
"point is invalid") "point is invalid")
// ErrCommitSyncLocalDataLoss is returned in the case that we receive a
// valid commit secret within the ChannelReestablish message from the
// remote node AND they advertise a RemoteCommitTailHeight higher than
// our current known height. This means we have lost some critical
// data, and must fail the channel and MUST NOT force close it. Instead
// we should wait for the remote to force close it, such that we can
// attempt to sweep our funds.
ErrCommitSyncLocalDataLoss = fmt.Errorf("possible local commitment " +
"state data loss")
// ErrCommitSyncRemoteDataLoss is returned in the case that we receive // ErrCommitSyncRemoteDataLoss is returned in the case that we receive
// a ChannelReestablish message from the remote that advertises a // a ChannelReestablish message from the remote that advertises a
// NextLocalCommitHeight that is lower than what they have already // NextLocalCommitHeight that is lower than what they have already
@ -101,6 +91,30 @@ var (
"state data loss") "state data loss")
) )
// ErrCommitSyncLocalDataLoss is returned in the case that we receive a valid
// commit secret within the ChannelReestablish message from the remote node AND
// they advertise a RemoteCommitTailHeight higher than our current known
// height. This means we have lost some critical data, and must fail the
// channel and MUST NOT force close it. Instead we should wait for the remote
// to force close it, such that we can attempt to sweep our funds. The
// commitment point needed to sweep the remote's force close is encapsuled.
type ErrCommitSyncLocalDataLoss struct {
// ChannelPoint is the identifier for the channel that experienced data
// loss.
ChannelPoint wire.OutPoint
// CommitPoint is the last unrevoked commit point, sent to us by the
// remote when we determined we had lost state.
CommitPoint *btcec.PublicKey
}
// Error returns a string representation of the local data loss error.
func (e *ErrCommitSyncLocalDataLoss) Error() string {
return fmt.Sprintf("ChannelPoint(%v) with CommitPoint(%x) had "+
"possible local commitment state data loss", e.ChannelPoint,
e.CommitPoint.SerializeCompressed())
}
// channelState is an enum like type which represents the current state of a // channelState is an enum like type which represents the current state of a
// particular channel. // particular channel.
// TODO(roasbeef): actually update state // TODO(roasbeef): actually update state
@ -3313,7 +3327,11 @@ func (lc *LightningChannel) ProcessChanSyncMsg(
if err != nil { if err != nil {
return nil, nil, nil, err return nil, nil, nil, err
} }
return nil, nil, nil, ErrCommitSyncLocalDataLoss
return nil, nil, nil, &ErrCommitSyncLocalDataLoss{
ChannelPoint: lc.channelState.FundingOutpoint,
CommitPoint: msg.LocalUnrevokedCommitPoint,
}
// If the height of our commitment chain reported by the remote party // If the height of our commitment chain reported by the remote party
// is behind our view of the chain, then they probably lost some state, // is behind our view of the chain, then they probably lost some state,

@ -3688,7 +3688,7 @@ func TestChanSyncFailure(t *testing.T) {
// Alice should detect from Bob's message that she lost state. // Alice should detect from Bob's message that she lost state.
_, _, _, err = aliceOld.ProcessChanSyncMsg(bobSyncMsg) _, _, _, err = aliceOld.ProcessChanSyncMsg(bobSyncMsg)
if err != ErrCommitSyncLocalDataLoss { if _, ok := err.(*ErrCommitSyncLocalDataLoss); !ok {
t.Fatalf("wrong error, expected "+ t.Fatalf("wrong error, expected "+
"ErrCommitSyncLocalDataLoss instead got: %v", "ErrCommitSyncLocalDataLoss instead got: %v",
err) err)
@ -4377,7 +4377,7 @@ func TestChanSyncInvalidLastSecret(t *testing.T) {
// Alice's former self should conclude that she possibly lost data as // Alice's former self should conclude that she possibly lost data as
// Bob is sending a valid commit secret for the latest state. // Bob is sending a valid commit secret for the latest state.
_, _, _, err = aliceOld.ProcessChanSyncMsg(bobChanSync) _, _, _, err = aliceOld.ProcessChanSyncMsg(bobChanSync)
if err != ErrCommitSyncLocalDataLoss { if _, ok := err.(*ErrCommitSyncLocalDataLoss); !ok {
t.Fatalf("wrong error, expected ErrCommitSyncLocalDataLoss "+ t.Fatalf("wrong error, expected ErrCommitSyncLocalDataLoss "+
"instead got: %v", err) "instead got: %v", err)
} }