lnwallet: update TestChanSyncFailure to pass with new borked update restriction

In this commit, we update the `TestChanSyncFailure` method to pass given
the new behavior around updating borked channel states. In order to do
this, we add a new method to allow the test to clear an existing channel
state. This method may be of independent use in other areas in the
codebase in the future as well.
This commit is contained in:
Olaoluwa Osuntokun 2019-03-08 17:55:42 -08:00
parent bc72691806
commit 33ad645f8c
No known key found for this signature in database
GPG Key ID: CE58F7F8E20FD9A2
2 changed files with 71 additions and 1 deletions

@ -110,7 +110,7 @@ var (
// ErrChanBorked is returned when a caller attempts to mutate a borked
// channel.
ErrChanBorked = fmt.Errorf("channel mutate borked channel")
ErrChanBorked = fmt.Errorf("cannot mutate borked channel")
)
// ChannelType is an enum-like type that describes one of several possible
@ -549,6 +549,16 @@ func (c *OpenChannel) ApplyChanStatus(status ChannelStatus) error {
return c.putChanStatus(status)
}
// ClearChanStatus allows the caller to clear a particular channel status from
// the primary channel status bit field. After this method returns, a call to
// HasChanStatus(status) should return false.
func (c *OpenChannel) ClearChanStatus(status ChannelStatus) error {
c.Lock()
defer c.Unlock()
return c.clearChanStatus(status)
}
// HasChanStatus returns true if the internal bitfield channel status of the
// target channel has the specified status bit set.
func (c *OpenChannel) HasChanStatus(status ChannelStatus) bool {
@ -864,6 +874,35 @@ func (c *OpenChannel) putChanStatus(status ChannelStatus) error {
return nil
}
func (c *OpenChannel) clearChanStatus(status ChannelStatus) error {
if err := c.Db.Update(func(tx *bbolt.Tx) error {
chanBucket, err := fetchChanBucket(
tx, c.IdentityPub, &c.FundingOutpoint, c.ChainHash,
)
if err != nil {
return err
}
channel, err := fetchOpenChannel(chanBucket, &c.FundingOutpoint)
if err != nil {
return err
}
// Unset this bit in the bitvector on disk.
status = channel.chanStatus & ^status
channel.chanStatus = status
return putOpenChannel(chanBucket, channel)
}); err != nil {
return err
}
// Update the in-memory representation to keep it in sync with the DB.
c.chanStatus = status
return nil
}
// putChannel serializes, and stores the current state of the channel in its
// entirety.
func putOpenChannel(chanBucket *bbolt.Bucket, channel *OpenChannel) error {

@ -3641,6 +3641,8 @@ func TestChanSyncFailure(t *testing.T) {
// advanceState is a helper method to fully advance the channel state
// by one.
advanceState := func() {
t.Helper()
// We'll kick off the test by having Bob send Alice an HTLC,
// then lock it in with a state transition.
var bobPreimage [32]byte
@ -3672,6 +3674,8 @@ func TestChanSyncFailure(t *testing.T) {
// halfAdvance is a helper method that sends a new commitment signature
// from Alice to Bob, but doesn't make Bob revoke his current state.
halfAdvance := func() {
t.Helper()
// We'll kick off the test by having Bob send Alice an HTLC,
// then lock it in with a state transition.
var bobPreimage [32]byte
@ -3707,6 +3711,8 @@ func TestChanSyncFailure(t *testing.T) {
// assertLocalDataLoss checks that aliceOld and bobChannel detects that
// Alice has lost state during sync.
assertLocalDataLoss := func(aliceOld *LightningChannel) {
t.Helper()
aliceSyncMsg, err := ChanSyncMsg(aliceOld.channelState)
if err != nil {
t.Fatalf("unable to produce chan sync msg: %v", err)
@ -3733,6 +3739,25 @@ func TestChanSyncFailure(t *testing.T) {
}
}
// clearBorkedState is a method that allows us to clear the borked
// state that will arise after the first chan message sync. We need to
// do this in order to be able to continue to update the commitment
// state for our test scenarios.
clearBorkedState := func() {
err = aliceChannel.channelState.ClearChanStatus(
channeldb.ChanStatusLocalDataLoss | channeldb.ChanStatusBorked,
)
if err != nil {
t.Fatalf("unable to update channel state: %v", err)
}
err = bobChannel.channelState.ClearChanStatus(
channeldb.ChanStatusLocalDataLoss | channeldb.ChanStatusBorked,
)
if err != nil {
t.Fatalf("unable to update channel state: %v", err)
}
}
// Start by advancing the state.
advanceState()
@ -3755,6 +3780,9 @@ func TestChanSyncFailure(t *testing.T) {
// Make sure the up-to-date channels still are in sync.
assertNoChanSyncNeeded(t, aliceChannel, bobChannel)
// Clear the borked state before we attempt to advance.
clearBorkedState()
// Advance the state again, and do the same check.
advanceState()
assertNoChanSyncNeeded(t, aliceChannel, bobChannel)
@ -3825,6 +3853,9 @@ func TestChanSyncFailure(t *testing.T) {
// Make sure the up-to-date channels still are good.
assertNoChanSyncNeeded(t, aliceChannel, bobChannel)
// Clear the borked state before we attempt to advance.
clearBorkedState()
// Finally check that Alice is also able to detect a wrong commit point
// when there's a pending remote commit.
halfAdvance()