lnwallet: modify ForceClose to disallow closing if local data loss

In this commit, we ensure that if a channel is detected to have local
data loss, then we don't allow a force close attempt, as this may not be
possible, or cause us to play an invalid state.
This commit is contained in:
Olaoluwa Osuntokun 2018-12-09 19:54:25 -08:00
parent b2b57314fa
commit 9e5723e1bc
No known key found for this signature in database
GPG Key ID: CE58F7F8E20FD9A2
2 changed files with 43 additions and 2 deletions

@ -5640,14 +5640,24 @@ func (lc *LightningChannel) ForceClose() (*LocalForceCloseSummary, error) {
lc.Lock()
defer lc.Unlock()
// If we've detected local data loss for this channel, then we won't
// allow a force close, as it may be the case that we have a dated
// version of the commitment, or this is actually a channel shell.
if lc.channelState.HasChanStatus(channeldb.ChanStatusLocalDataLoss) {
return nil, fmt.Errorf("cannot force close channel with "+
"state: %v", lc.channelState.ChanStatus())
}
commitTx, err := lc.getSignedCommitTx()
if err != nil {
return nil, err
}
localCommitment := lc.channelState.LocalCommitment
summary, err := NewLocalForceCloseSummary(lc.channelState,
lc.Signer, lc.pCache, commitTx, localCommitment)
summary, err := NewLocalForceCloseSummary(
lc.channelState, lc.Signer, lc.pCache, commitTx,
localCommitment,
)
if err != nil {
return nil, err
}

@ -17,6 +17,7 @@ import (
"github.com/btcsuite/btcutil"
"github.com/davecgh/go-spew/spew"
"github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/lnwire"
)
@ -6274,3 +6275,33 @@ func TestChannelRestoreCommitHeight(t *testing.T) {
bobChannel = restoreAndAssertCommitHeights(t, bobChannel, true, 0, 2, 1)
bobChannel = restoreAndAssertCommitHeights(t, bobChannel, true, 1, 2, 2)
}
// TestForceCloseFailLocalDataLoss tests that we don't allow a force close of a
// channel that's in a non-default state.
func TestForceCloseFailLocalDataLoss(t *testing.T) {
t.Parallel()
aliceChannel, _, cleanUp, err := CreateTestChannels()
if err != nil {
t.Fatalf("unable to create test channels: %v", err)
}
defer cleanUp()
// Now that we have our set of channels, we'll modify the channel state
// to have a non-default channel flag.
err = aliceChannel.channelState.ApplyChanStatus(
channeldb.ChanStatusLocalDataLoss,
)
if err != nil {
t.Fatalf("unable to apply channel state: %v", err)
}
// Due to the change above, if we attempt to force close this
// channel, we should fail as it isn't safe to force close a
// channel that isn't in the pure default state.
_, err = aliceChannel.ForceClose()
if err == nil {
t.Fatalf("expected force close to fail due to non-default " +
"chan state")
}
}