diff --git a/channeldb/channel.go b/channeldb/channel.go index bc2054886..0914f2424 100644 --- a/channeldb/channel.go +++ b/channeldb/channel.go @@ -2382,8 +2382,12 @@ type ChannelCloseSummary struct { // entails deleting all saved state within the database concerning this // channel. This method also takes a struct that summarizes the state of the // channel at closing, this compact representation will be the only component -// of a channel left over after a full closing. -func (c *OpenChannel) CloseChannel(summary *ChannelCloseSummary) error { +// of a channel left over after a full closing. It takes an optional set of +// channel statuses which will be written to the historical channel bucket. +// These statuses are used to record close initiators. +func (c *OpenChannel) CloseChannel(summary *ChannelCloseSummary, + statuses ...ChannelStatus) error { + c.Lock() defer c.Unlock() @@ -2461,6 +2465,11 @@ func (c *OpenChannel) CloseChannel(summary *ChannelCloseSummary) error { return err } + // Apply any additional statuses to the channel state. + for _, status := range statuses { + chanState.chanStatus |= status + } + err = putOpenChannel(historicalChanBucket, chanState) if err != nil { return err diff --git a/channeldb/channel_test.go b/channeldb/channel_test.go index ad7a69755..bd2ab8b73 100644 --- a/channeldb/channel_test.go +++ b/channeldb/channel_test.go @@ -1357,3 +1357,39 @@ func TestCloseInitiator(t *testing.T) { }) } } + +// TestCloseChannelStatus tests setting of a channel status on the historical +// channel on channel close. +func TestCloseChannelStatus(t *testing.T) { + cdb, cleanUp, err := makeTestDB() + if err != nil { + t.Fatalf("unable to make test database: %v", + err) + } + defer cleanUp() + + // Create an open channel. + channel := createTestChannel( + t, cdb, openChannelOption(), + ) + + if err := channel.CloseChannel( + &ChannelCloseSummary{ + ChanPoint: channel.FundingOutpoint, + RemotePub: channel.IdentityPub, + }, ChanStatusRemoteCloseInitiator, + ); err != nil { + t.Fatalf("unexpected error: %v", err) + } + + histChan, err := channel.Db.FetchHistoricalChannel( + &channel.FundingOutpoint, + ) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + if !histChan.HasChanStatus(ChanStatusRemoteCloseInitiator) { + t.Fatalf("channel should have status") + } +} diff --git a/channeldb/db.go b/channeldb/db.go index 6377df63a..c1cf46ba8 100644 --- a/channeldb/db.go +++ b/channeldb/db.go @@ -1159,8 +1159,9 @@ func (d *DB) AbandonChannel(chanPoint *wire.OutPoint, bestHeight uint32) error { } // Finally, we'll close the channel in the DB, and return back to the - // caller. - return dbChan.CloseChannel(summary) + // caller. We set ourselves as the close initiator because we abandoned + // the channel. + return dbChan.CloseChannel(summary, ChanStatusLocalCloseInitiator) } // syncVersions function is used for safe db version synchronization. It diff --git a/fundingmanager.go b/fundingmanager.go index 8484b9455..7913a11f6 100644 --- a/fundingmanager.go +++ b/fundingmanager.go @@ -1009,7 +1009,11 @@ func (f *fundingManager) advancePendingChannelState( LocalChanConfig: ch.LocalChanCfg, } - if err := ch.CloseChannel(closeInfo); err != nil { + // Close the channel with us as the initiator because we are + // timing the channel out. + if err := ch.CloseChannel( + closeInfo, channeldb.ChanStatusLocalCloseInitiator, + ); err != nil { return fmt.Errorf("failed closing channel "+ "%v: %v", ch.FundingOutpoint, err) } @@ -1639,7 +1643,11 @@ func (f *fundingManager) handleFundingCreated(fmsg *fundingCreatedMsg) { LocalChanConfig: completeChan.LocalChanCfg, } - if err := completeChan.CloseChannel(closeInfo); err != nil { + // Close the channel with us as the initiator because we are + // deciding to exit the funding flow due to an internal error. + if err := completeChan.CloseChannel( + closeInfo, channeldb.ChanStatusLocalCloseInitiator, + ); err != nil { fndgLog.Errorf("Failed closing channel %v: %v", completeChan.FundingOutpoint, err) }