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

     1  package automation
     2  
     3  import (
     4  	"context"
     5  	"time"
     6  
     7  	"github.com/decred/dcrlnd/channeldb"
     8  	"github.com/decred/dcrlnd/lncfg"
     9  	"github.com/decred/dcrlnd/lnrpc"
    10  )
    11  
    12  // Config are the config parameters for the automation server.
    13  type Config struct {
    14  	*lncfg.Automation
    15  
    16  	// CloseChannel should be set to the rpc server function that allows
    17  	// closing a channel.
    18  	CloseChannel func(in *lnrpc.CloseChannelRequest,
    19  		updateStream lnrpc.Lightning_CloseChannelServer) error
    20  
    21  	DB *channeldb.DB
    22  }
    23  
    24  // Server is set of automation services for dcrlnd nodes.
    25  type Server struct {
    26  	cfg       *Config
    27  	ctx       context.Context
    28  	cancelCtx func()
    29  }
    30  
    31  // NewServer creates a new automation server.
    32  func NewServer(cfg *Config) *Server {
    33  	ctx, cancel := context.WithCancel(context.Background())
    34  	s := &Server{
    35  		cfg:       cfg,
    36  		ctx:       ctx,
    37  		cancelCtx: cancel,
    38  	}
    39  	return s
    40  }
    41  
    42  // runForceCloseStaleChanReestablish autocloses channels where a remote peer
    43  // has been online without sending ChannelReestablish messages.
    44  func (s *Server) runForceCloseStaleChanReestablish() {
    45  	// Use a default ticker for 1 hour, but reduce if the threshold is lower
    46  	// than that (useful for tests).
    47  	forceCloseInterval := time.Duration(s.cfg.ForceCloseChanReestablishWait) * time.Second
    48  	tickerInterval := time.Hour
    49  	if forceCloseInterval < tickerInterval {
    50  		tickerInterval = forceCloseInterval
    51  	}
    52  	log.Debugf("Performing force close check for stale channels based on "+
    53  		"ChannelReestablish every %s", tickerInterval)
    54  
    55  	ticker := time.NewTicker(tickerInterval)
    56  	for {
    57  		select {
    58  		case <-s.ctx.Done():
    59  			ticker.Stop()
    60  			return
    61  		case <-ticker.C:
    62  		}
    63  
    64  		log.Debugf("Time to check channels for force close due to stale " +
    65  			"chan reestablish messages")
    66  
    67  		chans, err := s.cfg.DB.ChannelStateDB().FetchAllOpenChannels()
    68  		if err != nil {
    69  			log.Errorf("Unable to list open channels: %v", err)
    70  			continue
    71  		}
    72  
    73  		for _, c := range chans {
    74  			sid := c.ShortChannelID
    75  			waitTime, err := s.cfg.DB.ChannelStateDB().GetChanReestablishWaitTime(sid)
    76  			if err != nil {
    77  				log.Errorf("Unable to get chan reestablish msg "+
    78  					"times for %s: %v", sid, err)
    79  				continue
    80  			}
    81  
    82  			if waitTime < forceCloseInterval {
    83  				log.Tracef("Skipping autoclose of %s due to low "+
    84  					"wait time %s", sid, waitTime)
    85  				continue
    86  			}
    87  
    88  			// Start force close.
    89  			chanPoint := c.FundingOutpoint
    90  			log.Infof("Starting force-close attempt of channel %s (%s) "+
    91  				"due to channel reestablish msg wait time %s greater "+
    92  				"than max interval %s", chanPoint,
    93  				sid, waitTime, forceCloseInterval)
    94  			go func() {
    95  				req := &lnrpc.CloseChannelRequest{
    96  					ChannelPoint: lnrpc.OutpointToChanPoint(&chanPoint),
    97  					Force:        true,
    98  				}
    99  				err = s.cfg.CloseChannel(req, nil)
   100  				if err != nil {
   101  					log.Errorf("Unable to force-close channel %s: %v",
   102  						sid, err)
   103  				}
   104  			}()
   105  		}
   106  	}
   107  }
   108  
   109  func (s *Server) Start() error {
   110  	if s.cfg.ForceCloseChanReestablishWait > 0 {
   111  		go s.runForceCloseStaleChanReestablish()
   112  	}
   113  	return nil
   114  }
   115  
   116  func (s *Server) Stop() error {
   117  	s.cancelCtx()
   118  	return nil
   119  }