From 032eacb796ae2cebe8d6a38733049f2a46e2e72e Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Fri, 8 Mar 2019 16:04:31 -0800 Subject: [PATCH] channeldb: prevent mutating on-disk commitment state if channel is borked --- channeldb/channel.go | 48 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/channeldb/channel.go b/channeldb/channel.go index 42a53a7c..aba7fe25 100644 --- a/channeldb/channel.go +++ b/channeldb/channel.go @@ -107,6 +107,10 @@ var ( // mutate a channel that's been recovered. ErrNoRestoredChannelMutation = fmt.Errorf("cannot mutate restored " + "channel state") + + // ErrChanBorked is returned when a caller attempts to mutate a borked + // channel. + ErrChanBorked = fmt.Errorf("channel mutate borked channel") ) // ChannelType is an enum-like type that describes one of several possible @@ -807,6 +811,20 @@ func (c *OpenChannel) MarkBorked() error { return c.putChanStatus(ChanStatusBorked) } +// isBorked returns true if the channel has been marked as borked in the +// database. This requires an existing database transaction to already be +// active. +// +// NOTE: The primary mutex should already be held before this method is called. +func (c *OpenChannel) isBorked(chanBucket *bbolt.Bucket) (bool, error) { + channel, err := fetchOpenChannel(chanBucket, &c.FundingOutpoint) + if err != nil { + return false, err + } + + return channel.chanStatus != ChanStatusDefault, nil +} + // MarkCommitmentBroadcasted marks the channel as a commitment transaction has // been broadcast, either our own or the remote, and we should watch the chain // for it to confirm before taking any further action. @@ -978,6 +996,16 @@ func (c *OpenChannel) UpdateCommitment(newCommitment *ChannelCommitment) error { return err } + // If the channel is marked as borked, then for safety reasons, + // we shouldn't attempt any further updates. + isBorked, err := c.isBorked(chanBucket) + if err != nil { + return err + } + if isBorked { + return ErrChanBorked + } + if err = putChanInfo(chanBucket, c); err != nil { return fmt.Errorf("unable to store chan info: %v", err) } @@ -1408,6 +1436,16 @@ func (c *OpenChannel) AppendRemoteCommitChain(diff *CommitDiff) error { return err } + // If the channel is marked as borked, then for safety reasons, + // we shouldn't attempt any further updates. + isBorked, err := c.isBorked(chanBucket) + if err != nil { + return err + } + if isBorked { + return ErrChanBorked + } + // Any outgoing settles and fails necessarily have a // corresponding adds in this channel's forwarding packages. // Mark all of these as being fully processed in our forwarding @@ -1539,6 +1577,16 @@ func (c *OpenChannel) AdvanceCommitChainTail(fwdPkg *FwdPkg) error { return err } + // If the channel is marked as borked, then for safety reasons, + // we shouldn't attempt any further updates. + isBorked, err := c.isBorked(chanBucket) + if err != nil { + return err + } + if isBorked { + return ErrChanBorked + } + // Persist the latest preimage state to disk as the remote peer // has just added to our local preimage store, and given us a // new pending revocation key.