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 }