chainwatcher: only continue breach handling after successfully marked

closed

This commit makes the handoff procedure between the breachabiter and
chainwatcher use a function closure to mark the channel pending closed
in the DB. Doing it this way we know that the channel has been markd
pending closed in the DB when ProcessACK returns.

The reason we do this is that we really need a "two-way ACK" to have the
breacharbiter know it can go on with the breach handling. Earlier it
would just send the ACK on the channel and continue. This lead to a race
where breach handling could finish before the chain watcher had marked
the channel pending closed in the database, which again lead to the
breacharbiter failing to mark the channel fully closed.

We saw this causing flakes during itests.
This commit is contained in:
Johan T. Halseth committed 2021-05-06 12:37:11 +02:00
1 parent bdc1f3100d
commit ac49031396
3 files changed
+58 -35

No files matched your search

+20 -9
View File
@@ -100,11 +100,14 @@ type ChainArbitratorConfig struct {
MarkLinkInactive func(wire.OutPoint) error
// ContractBreach is a function closure that the ChainArbitrator will
// use to notify the breachArbiter about a contract breach. It should
// only return a non-nil error when the breachArbiter has preserved the
// necessary breach info for this channel point, and it is safe to mark
// the channel as pending close in the database.
ContractBreach func(wire.OutPoint, *lnwallet.BreachRetribution) error
// use to notify the breachArbiter about a contract breach. A callback
// should be passed that when called will mark the channel pending
// close in the databae. It should only return a non-nil error when the
// breachArbiter has preserved the necessary breach info for this
// channel point, and the callback has succeeded, meaning it is safe to
// stop watching the channel.
ContractBreach func(wire.OutPoint, *lnwallet.BreachRetribution,
func() error) error
// IsOurAddress is a function that returns true if the passed address
// is known to the underlying wallet. Otherwise, false should be
@@ -488,8 +491,12 @@ func (c *ChainArbitrator) Start() error {
notifier: c.cfg.Notifier,
signer: c.cfg.Signer,
isOurAddr: c.cfg.IsOurAddress,
contractBreach: func(retInfo *lnwallet.BreachRetribution) error {
return c.cfg.ContractBreach(chanPoint, retInfo)
contractBreach: func(retInfo *lnwallet.BreachRetribution,
markClosed func() error) error {
return c.cfg.ContractBreach(
chanPoint, retInfo, markClosed,
)
},
extractStateNumHint: lnwallet.GetStateNumHint,
},
@@ -1078,8 +1085,12 @@ func (c *ChainArbitrator) WatchNewChannel(newChan *channeldb.OpenChannel) error
notifier: c.cfg.Notifier,
signer: c.cfg.Signer,
isOurAddr: c.cfg.IsOurAddress,
contractBreach: func(retInfo *lnwallet.BreachRetribution) error {
return c.cfg.ContractBreach(chanPoint, retInfo)
contractBreach: func(retInfo *lnwallet.BreachRetribution,
markClosed func() error) error {
return c.cfg.ContractBreach(
chanPoint, retInfo, markClosed,
)
},
extractStateNumHint: lnwallet.GetStateNumHint,
},