github.com/decred/dcrlnd@v0.7.6/channel_notifier.go (about)

     1  package dcrlnd
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  
     7  	"github.com/decred/dcrd/dcrec/secp256k1/v4"
     8  	"github.com/decred/dcrd/wire"
     9  	"github.com/decred/dcrlnd/chanbackup"
    10  	"github.com/decred/dcrlnd/channeldb"
    11  	"github.com/decred/dcrlnd/channelnotifier"
    12  )
    13  
    14  // addrSource is an interface that allow us to get the addresses for a target
    15  // node. We'll need this in order to be able to properly proxy the
    16  // notifications to create SCBs.
    17  type addrSource interface {
    18  	// AddrsForNode returns all known addresses for the target node public
    19  	// key.
    20  	AddrsForNode(nodePub *secp256k1.PublicKey) ([]net.Addr, error)
    21  }
    22  
    23  // channelNotifier is an implementation of the chanbackup.ChannelNotifier
    24  // interface using the existing channelnotifier.ChannelNotifier struct. This
    25  // implementation allows us to satisfy all the dependencies of the
    26  // chanbackup.SubSwapper struct.
    27  type channelNotifier struct {
    28  	// chanNotifier is the based channel notifier that we'll proxy requests
    29  	// from.
    30  	chanNotifier *channelnotifier.ChannelNotifier
    31  
    32  	// addrs is an implementation of the addrSource interface that allows
    33  	// us to get the latest set of addresses for a given node. We'll need
    34  	// this to be able to create an SCB for new channels.
    35  	addrs addrSource
    36  }
    37  
    38  // SubscribeChans requests a new channel subscription relative to the initial
    39  // set of known channels. We use the knownChans as a synchronization point to
    40  // ensure that the chanbackup.SubSwapper does not miss any channel open or
    41  // close events in the period between when it's created, and when it requests
    42  // the channel subscription.
    43  //
    44  // NOTE: This is part of the chanbackup.ChannelNotifier interface.
    45  func (c *channelNotifier) SubscribeChans(startingChans map[wire.OutPoint]struct{}) (
    46  	*chanbackup.ChannelSubscription, error) {
    47  
    48  	ltndLog.Infof("Channel backup proxy channel notifier starting")
    49  
    50  	// TODO(roasbeef): read existing set of chans and diff
    51  
    52  	quit := make(chan struct{})
    53  	chanUpdates := make(chan chanbackup.ChannelEvent, 1)
    54  
    55  	// sendChanOpenUpdate is a closure that sends a ChannelEvent to the
    56  	// chanUpdates channel to inform subscribers about new pending or
    57  	// confirmed channels.
    58  	sendChanOpenUpdate := func(newOrPendingChan *channeldb.OpenChannel) {
    59  		nodeAddrs, err := c.addrs.AddrsForNode(
    60  			newOrPendingChan.IdentityPub,
    61  		)
    62  		if err != nil {
    63  			pub := newOrPendingChan.IdentityPub
    64  			ltndLog.Errorf("unable to fetch addrs for %x: %v",
    65  				pub.SerializeCompressed(), err)
    66  		}
    67  
    68  		chanEvent := chanbackup.ChannelEvent{
    69  			NewChans: []chanbackup.ChannelWithAddrs{
    70  				{
    71  					OpenChannel: newOrPendingChan,
    72  					Addrs:       nodeAddrs,
    73  				},
    74  			},
    75  		}
    76  
    77  		select {
    78  		case chanUpdates <- chanEvent:
    79  		case <-quit:
    80  			return
    81  		}
    82  	}
    83  
    84  	// In order to adhere to the interface, we'll proxy the events from the
    85  	// channel notifier to the sub-swapper in a format it understands.
    86  	go func() {
    87  		// First, we'll subscribe to the primary channel notifier so we can
    88  		// obtain events for new opened/closed channels.
    89  		chanSubscription, err := c.chanNotifier.SubscribeChannelEvents()
    90  		if err != nil {
    91  			panic(fmt.Sprintf("unable to subscribe to chans: %v",
    92  				err))
    93  		}
    94  
    95  		defer chanSubscription.Cancel()
    96  
    97  		for {
    98  			select {
    99  
   100  			// A new event has been sent by the chanNotifier, we'll
   101  			// filter out the events we actually care about and
   102  			// send them to the sub-swapper.
   103  			case e := <-chanSubscription.Updates():
   104  				// TODO(roasbeef): batch dispatch ntnfs
   105  
   106  				switch event := e.(type) {
   107  				// A new channel has been opened and is still
   108  				// pending. We can still create a backup, even
   109  				// if the final channel ID is not yet available.
   110  				case channelnotifier.PendingOpenChannelEvent:
   111  					pendingChan := event.PendingChannel
   112  					sendChanOpenUpdate(pendingChan)
   113  
   114  				// A new channel has been confirmed, we'll
   115  				// obtain the node address, then send to the
   116  				// sub-swapper.
   117  				case channelnotifier.OpenChannelEvent:
   118  					sendChanOpenUpdate(event.Channel)
   119  
   120  				// An existing channel has been closed, we'll
   121  				// send only the chanPoint of the closed
   122  				// channel to the sub-swapper.
   123  				case channelnotifier.ClosedChannelEvent:
   124  					chanPoint := event.CloseSummary.ChanPoint
   125  					closeType := event.CloseSummary.CloseType
   126  
   127  					// Because we see the contract as closed
   128  					// once our local force close TX
   129  					// confirms, the channel arbitrator
   130  					// already fires on this event. But
   131  					// because our funds can be in limbo for
   132  					// up to 2 weeks worst case we don't
   133  					// want to remove the crucial info we
   134  					// need for sweeping that time locked
   135  					// output before we've actually done so.
   136  					if closeType == channeldb.LocalForceClose {
   137  						ltndLog.Debugf("Channel %v "+
   138  							"was force closed by "+
   139  							"us, not removing "+
   140  							"from channel backup "+
   141  							"until fully resolved",
   142  							chanPoint)
   143  
   144  						continue
   145  					}
   146  
   147  					chanEvent := chanbackup.ChannelEvent{
   148  						ClosedChans: []wire.OutPoint{
   149  							chanPoint,
   150  						},
   151  					}
   152  
   153  					select {
   154  					case chanUpdates <- chanEvent:
   155  					case <-quit:
   156  						return
   157  					}
   158  
   159  				// A channel was fully resolved on chain. This
   160  				// should only really interest us if it was a
   161  				// locally force closed channel where we didn't
   162  				// remove the channel already when the close
   163  				// event was fired.
   164  				case channelnotifier.FullyResolvedChannelEvent:
   165  					chanEvent := chanbackup.ChannelEvent{
   166  						ClosedChans: []wire.OutPoint{
   167  							*event.ChannelPoint,
   168  						},
   169  					}
   170  
   171  					select {
   172  					case chanUpdates <- chanEvent:
   173  					case <-quit:
   174  						return
   175  					}
   176  				}
   177  
   178  			// The cancel method has been called, signalling us to
   179  			// exit
   180  			case <-quit:
   181  				return
   182  			}
   183  		}
   184  	}()
   185  
   186  	return &chanbackup.ChannelSubscription{
   187  		ChanUpdates: chanUpdates,
   188  		Cancel: func() {
   189  			close(quit)
   190  		},
   191  	}, nil
   192  }
   193  
   194  // A compile-time constraint to ensure channelNotifier implements
   195  // chanbackup.ChannelNotifier.
   196  var _ chanbackup.ChannelNotifier = (*channelNotifier)(nil)