From bda0e40dadaf0934006734bd14914ec66cc78591 Mon Sep 17 00:00:00 2001 From: "Johan T. Halseth" Date: Sun, 16 Sep 2018 10:40:11 +0200 Subject: [PATCH] fundingmanager: save markedOpen before marking the channel open This commit fixes a potential issue within the fundingmanager, where failing to write the channel opening state could cause the channel being marked open in the DB, but the opening state not being set. On startup this would cause the channel state machine to not be able to resume. We fix this by saving the channel opening state _first_. This works because saving the opening state is idempotent, and in case a channel is found pending at startup, it will re-register for confirmation notifications and re-do the process. --- fundingmanager.go | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/fundingmanager.go b/fundingmanager.go index c19dbe26..37f5563d 100644 --- a/fundingmanager.go +++ b/fundingmanager.go @@ -2005,8 +2005,23 @@ func (f *fundingManager) handleFundingConfirmation( fundingPoint := completeChan.FundingOutpoint chanID := lnwire.NewChanIDFromOutPoint(&fundingPoint) - // Now that the channel has been fully confirmed, we'll mark it as open - // within the database. + // TODO(roasbeef): ideally persistent state update for chan above + // should be abstracted + + // The funding transaction now being confirmed, we add this channel to + // the fundingManager's internal persistent state machine that we use + // to track the remaining process of the channel opening. This is + // useful to resume the opening process in case of restarts. We set the + // opening state before we mark the channel opened in the database, + // such that we can receover from one of the db writes failing. + err := f.saveChannelOpeningState(&fundingPoint, markedOpen, &shortChanID) + if err != nil { + return fmt.Errorf("error setting channel state to markedOpen: %v", + err) + } + + // Now that the channel has been fully confirmed and we successfully + // saved the opening state, we'll mark it as open within the database. if err := completeChan.MarkAsOpen(shortChanID); err != nil { return fmt.Errorf("error setting channel pending flag to false: "+ "%v", err) @@ -2016,23 +2031,6 @@ func (f *fundingManager) handleFundingConfirmation( // pending open to open. f.cfg.NotifyOpenChannelEvent(completeChan.FundingOutpoint) - // TODO(roasbeef): ideally persistent state update for chan above - // should be abstracted - - // The funding transaction now being confirmed, we add this channel to - // the fundingManager's internal persistent state machine that we use - // to track the remaining process of the channel opening. This is - // useful to resume the opening process in case of restarts. - // - // TODO(halseth): make the two db transactions (MarkChannelAsOpen and - // saveChannelOpeningState) atomic by doing them in the same transaction. - // Needed to be properly fault-tolerant. - err := f.saveChannelOpeningState(&fundingPoint, markedOpen, &shortChanID) - if err != nil { - return fmt.Errorf("error setting channel state to markedOpen: %v", - err) - } - // As there might already be an active link in the switch with an // outdated short chan ID, we'll instruct the switch to load the updated // short chan id from disk.