@@ -312,18 +312,8 @@ func newActiveChannelArbitrator(channel *channeldb.OpenChannel,
312
312
log .Tracef ("Creating ChannelArbitrator for ChannelPoint(%v)" ,
313
313
channel .FundingOutpoint )
314
314
315
- // We'll start by registering for a block epoch notifications so this
316
- // channel can keep track of the current state of the main chain.
317
- //
318
315
// TODO(roasbeef): fetch best height (or pass in) so can ensure block
319
316
// epoch delivers all the notifications to
320
- //
321
- // TODO(roasbeef): instead 1 block epoch that multi-plexes to the rest?
322
- // * reduces the number of goroutines
323
- blockEpoch , err := c .cfg .Notifier .RegisterBlockEpochNtfn (nil )
324
- if err != nil {
325
- return nil , err
326
- }
327
317
328
318
chanPoint := channel .FundingOutpoint
329
319
@@ -333,7 +323,6 @@ func newActiveChannelArbitrator(channel *channeldb.OpenChannel,
333
323
ChanPoint : chanPoint ,
334
324
Channel : c .getArbChannel (channel ),
335
325
ShortChanID : channel .ShortChanID (),
336
- BlockEpochs : blockEpoch ,
337
326
338
327
MarkCommitmentBroadcasted : channel .MarkCommitmentBroadcasted ,
339
328
MarkChannelClosed : func (summary * channeldb.ChannelCloseSummary ,
@@ -369,7 +358,6 @@ func newActiveChannelArbitrator(channel *channeldb.OpenChannel,
369
358
c .chanSource .Backend , arbCfg , c .cfg .ChainHash , chanPoint ,
370
359
)
371
360
if err != nil {
372
- blockEpoch .Cancel ()
373
361
return nil , err
374
362
}
375
363
@@ -385,7 +373,6 @@ func newActiveChannelArbitrator(channel *channeldb.OpenChannel,
385
373
386
374
pendingRemoteCommitment , err := channel .RemoteCommitChainTip ()
387
375
if err != nil && err != channeldb .ErrNoPendingCommit {
388
- blockEpoch .Cancel ()
389
376
return nil , err
390
377
}
391
378
if pendingRemoteCommitment != nil {
@@ -556,7 +543,6 @@ func (c *ChainArbitrator) Start() error {
556
543
arbCfg := ChannelArbitratorConfig {
557
544
ChanPoint : chanPoint ,
558
545
ShortChanID : closeChanInfo .ShortChanID ,
559
- BlockEpochs : blockEpoch ,
560
546
ChainArbitratorConfig : c .cfg ,
561
547
ChainEvents : & ChainEventSubscription {},
562
548
IsPendingClose : true ,
@@ -627,20 +613,100 @@ func (c *ChainArbitrator) Start() error {
627
613
}
628
614
}
629
615
630
- // Finally, we'll launch all the goroutines for each arbitrator so they
631
- // can carry out their duties.
616
+ // Launch all the goroutines for each arbitrator so they can carry out
617
+ // their duties.
632
618
for _ , arbitrator := range c .activeChannels {
633
619
if err := arbitrator .Start (); err != nil {
634
620
c .Stop ()
635
621
return err
636
622
}
637
623
}
638
624
625
+ // Subscribe to a single stream of block epoch notifications that we
626
+ // will dispatch to all active arbitrators.
627
+ blockEpoch , err := c .cfg .Notifier .RegisterBlockEpochNtfn (nil )
628
+ if err != nil {
629
+ return err
630
+ }
631
+
632
+ // Start our goroutine which will dispatch blocks to each arbitrator.
633
+ c .wg .Add (1 )
634
+ go func () {
635
+ defer c .wg .Done ()
636
+ c .dispatchBlocks (blockEpoch )
637
+ }()
638
+
639
639
// TODO(roasbeef): eventually move all breach watching here
640
640
641
641
return nil
642
642
}
643
643
644
+ // dispatchBlocks consumes a block epoch notification stream and dispatches
645
+ // blocks to each of the chain arb's active channel arbitrators. This function
646
+ // must be run in a goroutine.
647
+ func (c * ChainArbitrator ) dispatchBlocks (
648
+ blockEpoch * chainntnfs.BlockEpochEvent ) {
649
+
650
+ // getBlockChannels is a helper function which acquires the chain arb
651
+ // lock and returns a map of channel points to block channels.
652
+ getBlockChannels := func () map [wire.OutPoint ]chan <- int32 {
653
+ c .Lock ()
654
+ blocks := make (map [wire.OutPoint ]chan <- int32 )
655
+ for _ , channel := range c .activeChannels {
656
+ blocks [channel .cfg .ChanPoint ] = channel .blocks
657
+ }
658
+ c .Unlock ()
659
+
660
+ return blocks
661
+ }
662
+
663
+ // On exit, cancel our blocks subscription and close each block channel
664
+ // so that the arbitrators know they will no longer be receiving blocks.
665
+ defer func () {
666
+ blockEpoch .Cancel ()
667
+
668
+ blocks := getBlockChannels ()
669
+ for _ , block := range blocks {
670
+ close (block )
671
+ }
672
+ }()
673
+
674
+ // Consume block epochs until we receive the instruction to shutdown.
675
+ for {
676
+ select {
677
+ // Consume block epochs, exiting if our subscription is
678
+ // terminated.
679
+ case block , ok := <- blockEpoch .Epochs :
680
+ if ! ok {
681
+ log .Trace ("dispatchBlocks block epoch " +
682
+ "cancelled" )
683
+
684
+ return
685
+ }
686
+
687
+ // Get the set of currently active channels block
688
+ // subscription channels and dispatch the block to
689
+ // each.
690
+ for _ , blockChan := range getBlockChannels () {
691
+ select {
692
+ // Deliver the block to the arbitrator.
693
+ case blockChan <- block .Height :
694
+
695
+ // If the chain arb is shutting down, we don't
696
+ // need to deliver any more blocks (everything
697
+ // will be shutting down).
698
+ case <- c .quit :
699
+ return
700
+ }
701
+ }
702
+
703
+ // Exit if the chain arbitrator is shutting down.
704
+ case <- c .quit :
705
+ return
706
+ }
707
+ }
708
+ }
709
+
644
710
// publishClosingTxs will load any stored cooperative or unilater closing
645
711
// transactions and republish them. This helps ensure propagation of the
646
712
// transactions in the event that prior publications failed.
0 commit comments