@@ -270,6 +270,11 @@ type ChainArbitrator struct {
270270 // beat is the current best known blockbeat.
271271 beat chainio.Blockbeat
272272
273+ // resolvedChan is used to signal that the given channel outpoint has
274+ // been resolved onchain. Once received, chain arbitrator will perform
275+ // cleanups.
276+ resolvedChan chan wire.OutPoint
277+
273278 quit chan struct {}
274279
275280 wg sync.WaitGroup
@@ -286,6 +291,7 @@ func NewChainArbitrator(cfg ChainArbitratorConfig,
286291 activeWatchers : make (map [wire.OutPoint ]* chainWatcher ),
287292 chanSource : db ,
288293 quit : make (chan struct {}),
294+ resolvedChan : make (chan wire.OutPoint ),
289295 }
290296
291297 // Mount the block consumer.
@@ -459,6 +465,9 @@ func newActiveChannelArbitrator(channel *channeldb.OpenChannel,
459465 channel .ShortChanID (), htlc ,
460466 )
461467 },
468+ NotifyChannelResolved : func () {
469+ c .notifyChannelResolved (chanPoint )
470+ },
462471 }
463472
464473 // The final component needed is an arbitrator log that the arbitrator
@@ -474,14 +483,6 @@ func newActiveChannelArbitrator(channel *channeldb.OpenChannel,
474483 return nil , err
475484 }
476485
477- arbCfg .MarkChannelResolved = func () error {
478- if c .cfg .NotifyFullyResolvedChannel != nil {
479- c .cfg .NotifyFullyResolvedChannel (chanPoint )
480- }
481-
482- return c .ResolveContract (chanPoint )
483- }
484-
485486 // Finally, we'll need to construct a series of htlc Sets based on all
486487 // currently known valid commitments.
487488 htlcSets := make (map [HtlcSetKey ]htlcSet )
@@ -578,6 +579,17 @@ func (c *ChainArbitrator) Start(beat chainio.Blockbeat) error {
578579 // Set the current beat.
579580 c .beat = beat
580581
582+ // Start the goroutine which listens for signals to mark the channel as
583+ // resolved.
584+ //
585+ // NOTE: We must start this goroutine here we won't block the following
586+ // channel loading.
587+ c .wg .Add (1 )
588+ go func () {
589+ defer c .wg .Done ()
590+ c .resolveContracts ()
591+ }()
592+
581593 // First, we'll fetch all the channels that are still open, in order to
582594 // collect them within our set of active contracts.
583595 if err := c .loadOpenChannels (); err != nil {
@@ -697,6 +709,32 @@ func (c *ChainArbitrator) Start(beat chainio.Blockbeat) error {
697709 return nil
698710}
699711
712+ // resolveContracts listens to the `resolvedChan` to mark a given channel as
713+ // fully resolved.
714+ func (c * ChainArbitrator ) resolveContracts () {
715+ for {
716+ select {
717+ // The channel arbitrator signals that a given channel has been
718+ // resolved, we now update chain arbitrator's internal state for
719+ // this channel.
720+ case cp := <- c .resolvedChan :
721+ if c .cfg .NotifyFullyResolvedChannel != nil {
722+ c .cfg .NotifyFullyResolvedChannel (cp )
723+ }
724+
725+ err := c .ResolveContract (cp )
726+ if err != nil {
727+ log .Errorf ("Failed to resolve contract for " +
728+ "channel %v" , cp )
729+ }
730+
731+ // Exit if the chain arbitrator is shutting down.
732+ case <- c .quit :
733+ return
734+ }
735+ }
736+ }
737+
700738// dispatchBlocks consumes a block epoch notification stream and dispatches
701739// blocks to each of the chain arb's active channel arbitrators. This function
702740// must be run in a goroutine.
@@ -762,6 +800,16 @@ func (c *ChainArbitrator) handleBlockbeat(beat chainio.Blockbeat) {
762800 c .NotifyBlockProcessed (beat , err )
763801}
764802
803+ // notifyChannelResolved is used by the channel arbitrator to signal that a
804+ // given channel has been resolved.
805+ func (c * ChainArbitrator ) notifyChannelResolved (cp wire.OutPoint ) {
806+ select {
807+ case c .resolvedChan <- cp :
808+ case <- c .quit :
809+ return
810+ }
811+ }
812+
765813// republishClosingTxs will load any stored cooperative or unilateral closing
766814// transactions and republish them. This helps ensure propagation of the
767815// transactions in the event that prior publications failed.
@@ -1346,20 +1394,16 @@ func (c *ChainArbitrator) loadPendingCloseChannels() error {
13461394 closeChanInfo .ShortChanID , htlc ,
13471395 )
13481396 },
1397+ NotifyChannelResolved : func () {
1398+ c .notifyChannelResolved (chanPoint )
1399+ },
13491400 }
13501401 chanLog , err := newBoltArbitratorLog (
13511402 c .chanSource .Backend , arbCfg , c .cfg .ChainHash , chanPoint ,
13521403 )
13531404 if err != nil {
13541405 return err
13551406 }
1356- arbCfg .MarkChannelResolved = func () error {
1357- if c .cfg .NotifyFullyResolvedChannel != nil {
1358- c .cfg .NotifyFullyResolvedChannel (chanPoint )
1359- }
1360-
1361- return c .ResolveContract (chanPoint )
1362- }
13631407
13641408 // We create an empty map of HTLC's here since it's possible
13651409 // that the channel is in StateDefault and updateActiveHTLCs is
0 commit comments