diff --git a/channeldb/channel.go b/channeldb/channel.go index 4f5cd447..5bec7a47 100644 --- a/channeldb/channel.go +++ b/channeldb/channel.go @@ -1980,14 +1980,6 @@ func (c *OpenChannel) AppendRemoteCommitChain(diff *CommitDiff) error { return err } - // Clear unsigned acked remote updates. We are signing now for - // all that we've got. - err = chanBucket.Delete(unsignedAckedUpdatesKey) - if err != nil { - return fmt.Errorf("unable to clear dangling remote "+ - "updates: %v", err) - } - // TODO(roasbeef): use seqno to derive key for later LCP // With the bucket retrieved, we'll now serialize the commit @@ -2196,6 +2188,44 @@ func (c *OpenChannel) AdvanceCommitChainTail(fwdPkg *FwdPkg) error { return err } + // Persist the unsigned acked updates that are not included + // in their new commitment. + updateBytes := chanBucket.Get(unsignedAckedUpdatesKey) + if updateBytes == nil { + // If there are no updates to sign, we don't need to + // filter out any updates. + newRemoteCommit = &newCommit.Commitment + return nil + } + + r := bytes.NewReader(updateBytes) + unsignedUpdates, err := deserializeLogUpdates(r) + if err != nil { + return err + } + + var validUpdates []LogUpdate + for _, upd := range unsignedUpdates { + lIdx := upd.LogIndex + + // Filter for updates that are not on the remote + // commitment. + if lIdx >= newCommit.Commitment.RemoteLogIndex { + validUpdates = append(validUpdates, upd) + } + } + + var b bytes.Buffer + err = serializeLogUpdates(&b, validUpdates) + if err != nil { + return fmt.Errorf("unable to serialize log updates: %v", err) + } + + err = chanBucket.Put(unsignedAckedUpdatesKey, b.Bytes()) + if err != nil { + return fmt.Errorf("unable to store under unsignedAckedUpdatesKey: %v", err) + } + newRemoteCommit = &newCommit.Commitment return nil diff --git a/lnwallet/channel_test.go b/lnwallet/channel_test.go index 50931ef8..5307d867 100644 --- a/lnwallet/channel_test.go +++ b/lnwallet/channel_test.go @@ -7119,7 +7119,7 @@ func restoreAndAssert(t *testing.T, channel *LightningChannel, numAddsLocal, assertInLog(t, newChannel.remoteUpdateLog, numAddsRemote, numFailsRemote) } -// TesstChannelRestoreUpdateLogsFailedHTLC runs through a scenario where an +// TestChannelRestoreUpdateLogsFailedHTLC runs through a scenario where an // HTLC is added and failed, and asserts along the way that we would restore // the update logs of the channel to the expected state at any point. func TestChannelRestoreUpdateLogsFailedHTLC(t *testing.T) { @@ -7224,10 +7224,10 @@ func TestChannelRestoreUpdateLogsFailedHTLC(t *testing.T) { } // When sending a new commitment, Alice will add a pending commit to - // here remote chain. In this case it doesn't contain any new updates, - // so it won't affect the restoration. + // her remote chain. Since the unsigned acked updates aren't deleted + // until we receive a revocation, the fail should still be present. assertInLogs(t, aliceChannel, 1, 0, 0, 1) - restoreAndAssert(t, aliceChannel, 1, 0, 0, 0) + restoreAndAssert(t, aliceChannel, 1, 0, 0, 1) // When Alice receives Bob's revocation, the Fail is irrevocably locked // in on both sides. She should compact the logs, removing the HTLC and