From 11d975bd131bc0a5e49903e67714c74d6bd0d0a3 Mon Sep 17 00:00:00 2001 From: carla Date: Fri, 21 Feb 2020 13:24:23 +0200 Subject: [PATCH] channeldb: save channel status on channel close Add an optional channel status CloseChannel which will be stored on the hitsorical channel which is persisted at channel close. This status is used to set the close initiator for channels that do not complete the funding flow or we abandon. In follow up commits, this status will be used to record force and breach closes. The value is written to the historical channel bucket for diplay over rpc. --- channeldb/channel.go | 13 +++++++++++-- channeldb/channel_test.go | 36 ++++++++++++++++++++++++++++++++++++ channeldb/db.go | 5 +++-- fundingmanager.go | 12 ++++++++++-- 4 files changed, 60 insertions(+), 6 deletions(-) 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) }