When a ChannelArbitrator is finished with its duties, it attempts to stop itself but can't:
The channelAttendant goroutine calls advanceState which calls stateStep which hits this line if the state is StateFullyResolved:
|
if err := c.cfg.MarkChannelResolved(); err != nil { |
|
log.Errorf("unable to mark channel resolved: %v", err) |
|
return StateError, closeTx, err |
|
} |
MarkChannelResolved calls ResolveContract:
|
arbCfg.MarkChannelResolved = func() error { |
|
if c.cfg.NotifyFullyResolvedChannel != nil { |
|
c.cfg.NotifyFullyResolvedChannel(chanPoint) |
|
} |
|
|
|
return c.ResolveContract(chanPoint) |
ResolveContract calls Stop on the ChannelArbitrator:
|
if chainArb != nil { |
|
arbLog = chainArb.log |
|
|
|
if err := chainArb.Stop(); err != nil { |
|
log.Warnf("unable to stop ChannelArbitrator(%v): %v", |
|
chanPoint, err) |
|
} |
This will close the quit channel and wait for the waitgroup counter to go to zero. However, because this can be called from channelAttendant, the goroutine is waiting for itself to be cleaned up and will just hang. This doesn't cause the node to be unresponsive, but the ChannelArbitrator will sit there and not properly stop.
h/t @bitromortac
When a
ChannelArbitratoris finished with its duties, it attempts to stop itself but can't:The
channelAttendantgoroutine callsadvanceStatewhich callsstateStepwhich hits this line if the state isStateFullyResolved:lnd/contractcourt/channel_arbitrator.go
Lines 1280 to 1283 in e6fbaaf
MarkChannelResolvedcallsResolveContract:lnd/contractcourt/chain_arbitrator.go
Lines 399 to 404 in e6fbaaf
ResolveContractcallsStopon theChannelArbitrator:lnd/contractcourt/chain_arbitrator.go
Lines 465 to 471 in e6fbaaf
This will close the
quitchannel and wait for the waitgroup counter to go to zero. However, because this can be called fromchannelAttendant, the goroutine is waiting for itself to be cleaned up and will just hang. This doesn't cause the node to be unresponsive, but theChannelArbitratorwill sit there and not properly stop.h/t @bitromortac