github.com/mit-dci/lit@v0.0.0-20221102210550-8c3d3b49f2ce/lit.go (about)

     1  package main
     2  
     3  import (
     4  	"os"
     5  	"os/signal"
     6  	"runtime"
     7  	"syscall"
     8  	"time"
     9  
    10  	"github.com/mit-dci/lit/logging"
    11  
    12  	"github.com/mit-dci/lit/coinparam"
    13  	consts "github.com/mit-dci/lit/consts"
    14  	"github.com/mit-dci/lit/litrpc"
    15  	"github.com/mit-dci/lit/lnutil"
    16  	"github.com/mit-dci/lit/qln"
    17  
    18  	flags "github.com/jessevdk/go-flags"
    19  )
    20  
    21  type litConfig struct { // define a struct for usage with go-flags
    22  	// networks lit can try connecting to
    23  	Tn3host      string `long:"tn3" description:"Connect to bitcoin testnet3."`
    24  	Bc2host      string `long:"bc2" description:"bc2 full node."`
    25  	Lt4host      string `long:"lt4" description:"Connect to litecoin testnet4."`
    26  	Reghost      string `long:"reg" description:"Connect to bitcoin regtest."`
    27  	Litereghost  string `long:"litereg" description:"Connect to litecoin regtest."`
    28  	Dummyusdhost string `long:"dusd" description:"Connect to Dummy USD node."`
    29  	Rtvtchost    string `long:"rtvtc" description:"Connect to Vertcoin regtest node."`
    30  	Tvtchost     string `long:"tvtc" description:"Connect to Vertcoin test node."`
    31  	Vtchost      string `long:"vtc" description:"Connect to Vertcoin."`
    32  	// system specific configs
    33  	LitHomeDir string `long:"dir" description:"Specify Home Directory of lit as an absolute path."`
    34  	TrackerURL string `long:"tracker" description:"LN address tracker URL http|https://host:port"`
    35  	ConfigFile string
    36  	UnauthRPC  bool `long:"unauthrpc" description:"Enables unauthenticated Websocket RPC"`
    37  
    38  	// proxy
    39  	ProxyURL      string `long:"proxy" description:"SOCKS5 proxy to use for communicating with the network"`
    40  	LitProxyURL   string `long:"litproxy" description:"SOCKS5 proxy to use for Lit's network communications. Overridden by the proxy flag."`
    41  	ChainProxyURL string `long:"chainproxy" description:"SOCKS5 proxy to use for Wallit's network communications. Overridden by the proxy flag."`
    42  
    43  	// UPnP port forwarding and NAT Traversal
    44  	Nat string `long:"nat" description:"Toggle upnp or pmp NAT Traversal NAT Punching"`
    45  	//resync and tower config
    46  	Resync string `long:"resync" description:"Resync the given chain from the given tip (requires --tip) or from default params"`
    47  	Tip    int32  `long:"tip" description:"Given tip to resync from"`
    48  	Tower  bool   `long:"tower" description:"Watchtower: Run a watching node"`
    49  	Hard   bool   `short:"t" long:"hard" description:"Flag to set networks."`
    50  
    51  	// logging and debug parameters
    52  	LogLevel []bool `short:"v" description:"Set verbosity level to verbose (-v), very verbose (-vv) or very very verbose (-vvv)"`
    53  
    54  	// rpc server config
    55  	Rpcport uint16 `short:"p" long:"rpcport" description:"Set RPC port to connect to"`
    56  	Rpchost string `long:"rpchost" description:"Set RPC host to listen to"`
    57  	// auto config
    58  	AutoReconnect                   bool  `long:"autoReconnect" description:"Attempts to automatically reconnect to known peers periodically."`
    59  	AutoReconnectInterval           int64 `long:"autoReconnectInterval" description:"The interval (in seconds) the reconnect logic should be executed"`
    60  	AutoReconnectOnlyConnectedCoins bool  `long:"autoReconnectOnlyConnectedCoins" description:"Only reconnect to peers that we have channels with in a coin whose coin daemon is available"`
    61  	AutoListenPort                  int   `long:"autoListenPort" description:"When auto reconnect enabled, starts listening on this port"`
    62  	NoAutoListen                    bool  `long:"noautolisten" description:"Don't automatically listen on any ports."`
    63  	Params                          *coinparam.Params
    64  }
    65  
    66  var (
    67  	defaultLitHomeDirName                  = os.Getenv("HOME") + "/.lit"
    68  	defaultTrackerURL                      = "http://hubris.media.mit.edu:46580"
    69  	defaultKeyFileName                     = "privkey.hex"
    70  	defaultConfigFilename                  = "lit.conf"
    71  	defaultHomeDir                         = os.Getenv("HOME")
    72  	defaultRpcport                         = uint16(8001)
    73  	defaultRpchost                         = "localhost"
    74  	defaultAutoReconnect                   = true
    75  	defaultNoAutoListen                    = false
    76  	defaultAutoListenPort                  = 2448
    77  	defaultAutoReconnectInterval           = int64(60)
    78  	defaultUpnPFlag                        = false
    79  	defaultLogLevel                        = 0
    80  	defaultAutoReconnectOnlyConnectedCoins = false
    81  	defaultUnauthRPC                       = false
    82  )
    83  
    84  func fileExists(name string) bool {
    85  	if _, err := os.Stat(name); err != nil {
    86  		if os.IsNotExist(err) {
    87  			return false
    88  		}
    89  	}
    90  	return true
    91  }
    92  
    93  // newConfigParser returns a new command line flags parser.
    94  func newConfigParser(conf *litConfig, options flags.Options) *flags.Parser {
    95  	parser := flags.NewParser(conf, options)
    96  	return parser
    97  }
    98  func linkWallets(node *qln.LitNode, key *[32]byte, conf *litConfig) error {
    99  	// for now, wallets are linked to the litnode on startup, and
   100  	// can't appear / disappear while it's running.  Later
   101  	// could support dynamically adding / removing wallets
   102  
   103  	// order matters; the first registered wallet becomes the default
   104  
   105  	var err error
   106  	// try regtest
   107  	if !lnutil.NopeString(conf.Reghost) {
   108  		p := &coinparam.RegressionNetParams
   109  		logging.Infof("reg: %s\n", conf.Reghost)
   110  		resync := false
   111  		conf.Tip = consts.BitcoinRegtestBHeight
   112  		if conf.Resync == "reg" {
   113  			if conf.Tip < consts.BitcoinRegtestBHeight {
   114  				conf.Tip = consts.BitcoinRegtestBHeight
   115  			}
   116  			resync = true
   117  		}
   118  		err = node.LinkBaseWallet(key, conf.Tip, resync,
   119  			conf.Tower, conf.Reghost, conf.ChainProxyURL, p)
   120  		if err != nil {
   121  			return err
   122  		}
   123  	}
   124  	// try testnet3
   125  	if !lnutil.NopeString(conf.Tn3host) {
   126  		p := &coinparam.TestNet3Params
   127  		resync := false
   128  		conf.Tip = consts.BitcoinTestnet3BHeight
   129  		if conf.Resync == "tn3" {
   130  			if conf.Tip < consts.BitcoinTestnet3BHeight {
   131  				conf.Tip = consts.BitcoinTestnet3BHeight
   132  			}
   133  			resync = true
   134  		}
   135  		err = node.LinkBaseWallet(
   136  			key, conf.Tip, resync, conf.Tower,
   137  			conf.Tn3host, conf.ChainProxyURL, p)
   138  		if err != nil {
   139  			return err
   140  		}
   141  	}
   142  	// try litecoin regtest
   143  	if !lnutil.NopeString(conf.Litereghost) {
   144  		p := &coinparam.LiteRegNetParams
   145  		resync := false
   146  		conf.Tip = consts.BitcoinRegtestBHeight
   147  		if conf.Resync == "ltcreg" {
   148  			if conf.Tip < consts.BitcoinRegtestBHeight {
   149  				conf.Tip = consts.BitcoinRegtestBHeight // birth heights are the same for btc and ltc regtests
   150  			}
   151  			resync = true
   152  		}
   153  		err = node.LinkBaseWallet(key, conf.Tip, resync,
   154  			conf.Tower, conf.Litereghost, conf.ChainProxyURL, p)
   155  		if err != nil {
   156  			return err
   157  		}
   158  	}
   159  	// try litecoin testnet4
   160  	if !lnutil.NopeString(conf.Lt4host) {
   161  		p := &coinparam.LiteCoinTestNet4Params
   162  		resync := false
   163  		conf.Tip = p.StartHeight
   164  		if conf.Resync == "ltctn" {
   165  			if conf.Tip < 1 {
   166  				conf.Tip = 1
   167  			}
   168  			resync = true
   169  		}
   170  		err = node.LinkBaseWallet(
   171  			key, p.StartHeight, resync, conf.Tower,
   172  			conf.Lt4host, conf.ChainProxyURL, p)
   173  		if err != nil {
   174  			return err
   175  		}
   176  	}
   177  	// try vertcoin testnet
   178  	if !lnutil.NopeString(conf.Tvtchost) {
   179  		p := &coinparam.VertcoinTestNetParams
   180  		resync := false
   181  		if conf.Resync == "vtctn" {
   182  			resync = true
   183  		}
   184  		err = node.LinkBaseWallet(
   185  			key, consts.VertcoinTestnetBHeight, resync, conf.Tower,
   186  			conf.Tvtchost, conf.ChainProxyURL, p)
   187  		if err != nil {
   188  			return err
   189  		}
   190  	}
   191  	// try vertcoin mainnet
   192  	if !lnutil.NopeString(conf.Vtchost) {
   193  		p := &coinparam.VertcoinParams
   194  		resync := false
   195  		conf.Tip = p.StartHeight
   196  		if conf.Resync == "ltctn" {
   197  			if conf.Tip < 1 {
   198  				conf.Tip = 1
   199  			}
   200  			resync = true
   201  		}
   202  		err = node.LinkBaseWallet(
   203  			key, conf.Tip, resync, conf.Tower,
   204  			conf.Vtchost, conf.ChainProxyURL, p)
   205  		if err != nil {
   206  			return err
   207  		}
   208  	}
   209  	// try dummyusd
   210  	if !lnutil.NopeString(conf.Dummyusdhost) {
   211  		p := &coinparam.DummyUsdNetParams
   212  		logging.Infof("Dummyusd: %s\n", conf.Dummyusdhost)
   213  		resync := false
   214  		conf.Tip = p.StartHeight
   215  		if conf.Resync == "dusd" {
   216  			if conf.Tip < 1 {
   217  				conf.Tip = 1
   218  			}
   219  			resync = true
   220  		}
   221  		err = node.LinkBaseWallet(key, consts.BitcoinRegtestBHeight, resync,
   222  			conf.Tower, conf.Dummyusdhost, conf.ChainProxyURL, p)
   223  		if err != nil {
   224  			return err
   225  		}
   226  	}
   227  
   228  	// try vertcoin regtest
   229  	if !lnutil.NopeString(conf.Rtvtchost) {
   230  		p := &coinparam.VertcoinRegTestParams
   231  		resync := false
   232  		conf.Tip = p.StartHeight
   233  		if conf.Resync == "rtvtc" {
   234  			if conf.Tip < 1 {
   235  				conf.Tip = 1
   236  			}
   237  			resync = true
   238  		}
   239  
   240  		err = node.LinkBaseWallet(
   241  			key, consts.BitcoinRegtestBHeight, resync, conf.Tower,
   242  			conf.Rtvtchost, conf.ChainProxyURL, p)
   243  		if err != nil {
   244  			return err
   245  		}
   246  	}
   247  	return nil
   248  }
   249  
   250  func main() {
   251  
   252  	conf := litConfig{
   253  		LitHomeDir:                      defaultLitHomeDirName,
   254  		Rpcport:                         defaultRpcport,
   255  		Rpchost:                         defaultRpchost,
   256  		TrackerURL:                      defaultTrackerURL,
   257  		AutoReconnect:                   defaultAutoReconnect,
   258  		NoAutoListen:                    defaultNoAutoListen,
   259  		AutoListenPort:                  defaultAutoListenPort,
   260  		AutoReconnectInterval:           defaultAutoReconnectInterval,
   261  		AutoReconnectOnlyConnectedCoins: defaultAutoReconnectOnlyConnectedCoins,
   262  		UnauthRPC:                       defaultUnauthRPC,
   263  	}
   264  
   265  	key := litSetup(&conf)
   266  	if conf.ProxyURL != "" {
   267  		conf.LitProxyURL = conf.ProxyURL
   268  		conf.ChainProxyURL = conf.ProxyURL
   269  	}
   270  
   271  	// SIGQUIT handler for debugging
   272  	go func() {
   273  		sigs := make(chan os.Signal, 1)
   274  		signal.Notify(sigs, syscall.SIGQUIT)
   275  		buf := make([]byte, 1<<20)
   276  		for {
   277  			<-sigs
   278  			stacklen := runtime.Stack(buf, true)
   279  			logging.Warnf("=== received SIGQUIT ===\n*** goroutine dump...\n%s\n*** end\n", buf[:stacklen])
   280  		}
   281  	}()
   282  
   283  	// Setup LN node.  Activate Tower if in hard mode.
   284  	// give node and below file pathof lit home directory
   285  	node, err := qln.NewLitNode(key, conf.LitHomeDir, conf.TrackerURL, conf.LitProxyURL, conf.Nat)
   286  	if err != nil {
   287  		logging.Fatal(err)
   288  	}
   289  
   290  	// node is up; link wallets based on args
   291  	err = linkWallets(node, key, &conf)
   292  	if err != nil {
   293  		// if we don't link wallet, we can still continue, no worries.
   294  		logging.Error(err)
   295  	}
   296  
   297  	rpcl := new(litrpc.LitRPC)
   298  	rpcl.Node = node
   299  	rpcl.OffButton = make(chan bool, 1)
   300  	node.RPC = rpcl
   301  
   302  	// "conf.UnauthRPC" enables unauthenticated Websocket RPC. Default - false.
   303  	if conf.UnauthRPC {
   304  		go litrpc.RPCListen(rpcl, conf.Rpchost, conf.Rpcport)
   305  	}
   306  
   307  	// conf.AutoReconnect Attempts to automatically reconnect to known peers periodically. Default - true
   308  	// conf.NoAutoListen Don't automatically listen on any ports. Default - false
   309  	if conf.AutoReconnect && !conf.NoAutoListen {
   310  		node.AutoReconnect(conf.AutoListenPort, conf.AutoReconnectInterval, conf.AutoReconnectOnlyConnectedCoins)
   311  	}
   312  
   313  	<-rpcl.OffButton
   314  	logging.Infof("Got stop request\n")
   315  	time.Sleep(time.Second)
   316  
   317  	return
   318  	// New directory being created over at PWD
   319  	// conf file being created at /
   320  }