lnwallet: send invalid commitment secret if restored chan in ChanSyncMsg

In this commit, we modify the `ChanSyncMsg` to send an invalid
commitment secret in `ChanSyncMsg`. We do this in order to force the
remote party to force close off-chain, if we're restoring a channel from
scratch and we never had any state updates within the channel. We need
to do this, as otherwise the remote party will think we can resume as
they're able to verify their own commit secret for state zero.
This commit is contained in:
Olaoluwa Osuntokun 2019-03-10 16:42:12 -07:00
parent 3e866c6cc5
commit fc8337b146
No known key found for this signature in database
GPG Key ID: CE58F7F8E20FD9A2
2 changed files with 49 additions and 29 deletions

@ -3531,7 +3531,14 @@ func (lc *LightningChannel) ProcessChanSyncMsg(
// it.
// 3. We didn't get the last RevokeAndAck message they sent, so they'll
// re-send it.
func ChanSyncMsg(c *channeldb.OpenChannel) (*lnwire.ChannelReestablish, error) {
//
// The isRestoredChan bool indicates if we need to craft a chan sync message
// for a channel that's been restored. If this is a restored channel, then
// we'll modify our typical chan sync message to ensure they force close even
// if we're on the very first state.
func ChanSyncMsg(c *channeldb.OpenChannel,
isRestoredChan bool) (*lnwire.ChannelReestablish, error) {
c.Lock()
defer c.Unlock()
@ -3572,6 +3579,13 @@ func ChanSyncMsg(c *channeldb.OpenChannel) (*lnwire.ChannelReestablish, error) {
return nil, err
}
// If we've restored this channel, then we'll purposefully give them an
// invalid LocalUnrevokedCommitPoint so they'll force close the channel
// allowing us to sweep our funds.
if isRestoredChan {
currentCommitSecret[0] ^= 1
}
return &lnwire.ChannelReestablish{
ChanID: lnwire.NewChanIDFromOutPoint(
&c.FundingOutpoint,
@ -3632,7 +3646,7 @@ func (lc *LightningChannel) computeView(view *htlcView, remoteChain bool,
// will remove their corresponding added HTLCs. The resulting filtered
// view will only have Add entries left, making it easy to compare the
// channel constraints to the final commitment state. If any fee
// updates are found in the logs, the comitment fee rate should be
// updates are found in the logs, the commitment fee rate should be
// changed, so we'll also set the feePerKw to this new value.
filteredHTLCView := lc.evaluateHTLCView(view, &ourBalance,
&theirBalance, nextHeight, remoteChain, updateState)
@ -5086,12 +5100,14 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, signer input.Si
// Next, we'll obtain HTLC resolutions for all the outgoing HTLC's we
// had on their commitment transaction.
htlcResolutions, err := extractHtlcResolutions(
SatPerKWeight(remoteCommit.FeePerKw), false, signer, remoteCommit.Htlcs,
keyRing, &chanState.LocalChanCfg, &chanState.RemoteChanCfg,
*commitSpend.SpenderTxHash, pCache,
SatPerKWeight(remoteCommit.FeePerKw), false, signer,
remoteCommit.Htlcs, keyRing, &chanState.LocalChanCfg,
&chanState.RemoteChanCfg, *commitSpend.SpenderTxHash,
pCache,
)
if err != nil {
return nil, fmt.Errorf("unable to create htlc resolutions: %v", err)
return nil, fmt.Errorf("unable to create htlc "+
"resolutions: %v", err)
}
commitTxBroadcast := commitSpend.SpendingTx
@ -5101,7 +5117,8 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, signer input.Si
// transaction.
selfP2WKH, err := input.CommitScriptUnencumbered(keyRing.NoDelayKey)
if err != nil {
return nil, fmt.Errorf("unable to create self commit script: %v", err)
return nil, fmt.Errorf("unable to create self commit "+
"script: %v", err)
}
var (
@ -5159,7 +5176,10 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, signer input.Si
}
// Attempt to add a channel sync message to the close summary.
chanSync, err := ChanSyncMsg(chanState)
chanSync, err := ChanSyncMsg(
chanState,
chanState.HasChanStatus(channeldb.ChanStatusRestored),
)
if err != nil {
walletLog.Errorf("ChannelPoint(%v): unable to create channel sync "+
"message: %v", chanState.FundingOutpoint, err)

@ -2532,7 +2532,7 @@ func assertNoChanSyncNeeded(t *testing.T, aliceChannel *LightningChannel,
_, _, line, _ := runtime.Caller(1)
aliceChanSyncMsg, err := ChanSyncMsg(aliceChannel.channelState)
aliceChanSyncMsg, err := ChanSyncMsg(aliceChannel.channelState, false)
if err != nil {
t.Fatalf("line #%v: unable to produce chan sync msg: %v",
line, err)
@ -2547,7 +2547,7 @@ func assertNoChanSyncNeeded(t *testing.T, aliceChannel *LightningChannel,
"instead wants to send: %v", line, spew.Sdump(bobMsgsToSend))
}
bobChanSyncMsg, err := ChanSyncMsg(bobChannel.channelState)
bobChanSyncMsg, err := ChanSyncMsg(bobChannel.channelState, false)
if err != nil {
t.Fatalf("line #%v: unable to produce chan sync msg: %v",
line, err)
@ -2780,11 +2780,11 @@ func TestChanSyncOweCommitment(t *testing.T) {
// Bob doesn't get this message so upon reconnection, they need to
// synchronize. Alice should conclude that she owes Bob a commitment,
// while Bob should think he's properly synchronized.
aliceSyncMsg, err := ChanSyncMsg(aliceChannel.channelState)
aliceSyncMsg, err := ChanSyncMsg(aliceChannel.channelState, false)
if err != nil {
t.Fatalf("unable to produce chan sync msg: %v", err)
}
bobSyncMsg, err := ChanSyncMsg(bobChannel.channelState)
bobSyncMsg, err := ChanSyncMsg(bobChannel.channelState, false)
if err != nil {
t.Fatalf("unable to produce chan sync msg: %v", err)
}
@ -3093,11 +3093,11 @@ func TestChanSyncOweRevocation(t *testing.T) {
// If we fetch the channel sync messages at this state, then Alice
// should report that she owes Bob a revocation message, while Bob
// thinks they're fully in sync.
aliceSyncMsg, err := ChanSyncMsg(aliceChannel.channelState)
aliceSyncMsg, err := ChanSyncMsg(aliceChannel.channelState, false)
if err != nil {
t.Fatalf("unable to produce chan sync msg: %v", err)
}
bobSyncMsg, err := ChanSyncMsg(bobChannel.channelState)
bobSyncMsg, err := ChanSyncMsg(bobChannel.channelState, false)
if err != nil {
t.Fatalf("unable to produce chan sync msg: %v", err)
}
@ -3261,11 +3261,11 @@ func TestChanSyncOweRevocationAndCommit(t *testing.T) {
// If we now attempt to resync, then Alice should conclude that she
// doesn't need any further updates, while Bob concludes that he needs
// to re-send both his revocation and commit sig message.
aliceSyncMsg, err := ChanSyncMsg(aliceChannel.channelState)
aliceSyncMsg, err := ChanSyncMsg(aliceChannel.channelState, false)
if err != nil {
t.Fatalf("unable to produce chan sync msg: %v", err)
}
bobSyncMsg, err := ChanSyncMsg(bobChannel.channelState)
bobSyncMsg, err := ChanSyncMsg(bobChannel.channelState, false)
if err != nil {
t.Fatalf("unable to produce chan sync msg: %v", err)
}
@ -3470,11 +3470,11 @@ func TestChanSyncOweRevocationAndCommitForceTransition(t *testing.T) {
// Now if we attempt to synchronize states at this point, Alice should
// detect that she owes nothing, while Bob should re-send both his
// RevokeAndAck as well as his commitment message.
aliceSyncMsg, err := ChanSyncMsg(aliceChannel.channelState)
aliceSyncMsg, err := ChanSyncMsg(aliceChannel.channelState, false)
if err != nil {
t.Fatalf("unable to produce chan sync msg: %v", err)
}
bobSyncMsg, err := ChanSyncMsg(bobChannel.channelState)
bobSyncMsg, err := ChanSyncMsg(bobChannel.channelState, false)
if err != nil {
t.Fatalf("unable to produce chan sync msg: %v", err)
}
@ -3674,11 +3674,11 @@ func TestChanSyncFailure(t *testing.T) {
assertLocalDataLoss := func(aliceOld *LightningChannel) {
t.Helper()
aliceSyncMsg, err := ChanSyncMsg(aliceOld.channelState)
aliceSyncMsg, err := ChanSyncMsg(aliceOld.channelState, false)
if err != nil {
t.Fatalf("unable to produce chan sync msg: %v", err)
}
bobSyncMsg, err := ChanSyncMsg(bobChannel.channelState)
bobSyncMsg, err := ChanSyncMsg(bobChannel.channelState, false)
if err != nil {
t.Fatalf("unable to produce chan sync msg: %v", err)
}
@ -3752,7 +3752,7 @@ func TestChanSyncFailure(t *testing.T) {
// If we remove the recovery options from Bob's message, Alice cannot
// tell if she lost state, since Bob might be lying. She still should
// be able to detect that chains cannot be synced.
bobSyncMsg, err := ChanSyncMsg(bobChannel.channelState)
bobSyncMsg, err := ChanSyncMsg(bobChannel.channelState, false)
if err != nil {
t.Fatalf("unable to produce chan sync msg: %v", err)
}
@ -3766,7 +3766,7 @@ func TestChanSyncFailure(t *testing.T) {
// If Bob lies about the NextLocalCommitHeight, making it greater than
// what Alice expect, she cannot tell for sure whether she lost state,
// but should detect the desync.
bobSyncMsg, err = ChanSyncMsg(bobChannel.channelState)
bobSyncMsg, err = ChanSyncMsg(bobChannel.channelState, false)
if err != nil {
t.Fatalf("unable to produce chan sync msg: %v", err)
}
@ -3779,7 +3779,7 @@ func TestChanSyncFailure(t *testing.T) {
// If Bob's NextLocalCommitHeight is lower than what Alice expects, Bob
// probably lost state.
bobSyncMsg, err = ChanSyncMsg(bobChannel.channelState)
bobSyncMsg, err = ChanSyncMsg(bobChannel.channelState, false)
if err != nil {
t.Fatalf("unable to produce chan sync msg: %v", err)
}
@ -3792,7 +3792,7 @@ func TestChanSyncFailure(t *testing.T) {
// If Alice and Bob's states are in sync, but Bob is sending the wrong
// LocalUnrevokedCommitPoint, Alice should detect this.
bobSyncMsg, err = ChanSyncMsg(bobChannel.channelState)
bobSyncMsg, err = ChanSyncMsg(bobChannel.channelState, false)
if err != nil {
t.Fatalf("unable to produce chan sync msg: %v", err)
}
@ -3821,7 +3821,7 @@ func TestChanSyncFailure(t *testing.T) {
// when there's a pending remote commit.
halfAdvance()
bobSyncMsg, err = ChanSyncMsg(bobChannel.channelState)
bobSyncMsg, err = ChanSyncMsg(bobChannel.channelState, false)
if err != nil {
t.Fatalf("unable to produce chan sync msg: %v", err)
}
@ -3909,11 +3909,11 @@ func TestChannelRetransmissionFeeUpdate(t *testing.T) {
// Bob doesn't get this message so upon reconnection, they need to
// synchronize. Alice should conclude that she owes Bob a commitment,
// while Bob should think he's properly synchronized.
aliceSyncMsg, err := ChanSyncMsg(aliceChannel.channelState)
aliceSyncMsg, err := ChanSyncMsg(aliceChannel.channelState, false)
if err != nil {
t.Fatalf("unable to produce chan sync msg: %v", err)
}
bobSyncMsg, err := ChanSyncMsg(bobChannel.channelState)
bobSyncMsg, err := ChanSyncMsg(bobChannel.channelState, false)
if err != nil {
t.Fatalf("unable to produce chan sync msg: %v", err)
}
@ -4357,11 +4357,11 @@ func TestChanSyncInvalidLastSecret(t *testing.T) {
}
// Next, we'll produce the ChanSync messages for both parties.
aliceChanSync, err := ChanSyncMsg(aliceChannel.channelState)
aliceChanSync, err := ChanSyncMsg(aliceChannel.channelState, false)
if err != nil {
t.Fatalf("unable to generate chan sync msg: %v", err)
}
bobChanSync, err := ChanSyncMsg(bobChannel.channelState)
bobChanSync, err := ChanSyncMsg(bobChannel.channelState, false)
if err != nil {
t.Fatalf("unable to generate chan sync msg: %v", err)
}