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.
This commit is contained in:
carla 2020-02-21 13:24:23 +02:00
parent d3cb6ad869
commit 11d975bd13
No known key found for this signature in database
GPG Key ID: 4CA7FE54A6213C91
4 changed files with 60 additions and 6 deletions

@ -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

@ -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")
}
}

@ -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

@ -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)
}