decred.org/dcrdex@v1.0.5/server/cmd/dcrdex/main.go (about) 1 // This code is available on the terms of the project LICENSE.md file, 2 // also available online at https://blueoakcouncil.org/license/1.0.0. 3 4 package main 5 6 import ( 7 "context" 8 "crypto/sha256" 9 "fmt" 10 "net/http" 11 _ "net/http/pprof" 12 "os" 13 "runtime" 14 "runtime/pprof" 15 "strings" 16 "sync" 17 18 "decred.org/dcrdex/dex" 19 "decred.org/dcrdex/dex/encode" 20 "decred.org/dcrdex/server/admin" 21 _ "decred.org/dcrdex/server/asset/importall" 22 dexsrv "decred.org/dcrdex/server/dex" 23 "github.com/decred/dcrd/dcrec/secp256k1/v4" 24 ) 25 26 func mainCore(ctx context.Context) error { 27 // Parse the configuration file, and setup logger. 28 cfg, opts, err := loadConfig() 29 if err != nil { 30 fmt.Printf("Failed to load dcrdex config: %s\n", err.Error()) 31 return err 32 } 33 defer func() { 34 if logRotator != nil { 35 logRotator.Close() 36 } 37 }() 38 39 if cfg.ValidateMarkets { 40 return dexsrv.ValidateConfigFile(cfg.MarketsConfPath, cfg.Network, log.SubLogger("V")) 41 } 42 43 // Request admin server password if admin server is enabled and 44 // server password is not set in config. 45 var adminSrvAuthSHA [32]byte 46 if cfg.AdminSrvOn { 47 if len(cfg.AdminSrvPW) == 0 { 48 adminSrvAuthSHA, err = admin.PasswordHashPrompt(ctx, "Admin interface password: ") 49 if err != nil { 50 return fmt.Errorf("cannot use password: %v", err) 51 } 52 } else { 53 adminSrvAuthSHA = sha256.Sum256(cfg.AdminSrvPW) 54 encode.ClearBytes(cfg.AdminSrvPW) 55 } 56 } 57 58 if opts.CPUProfile != "" { 59 var f *os.File 60 f, err = os.Create(opts.CPUProfile) 61 if err != nil { 62 return err 63 } 64 err = pprof.StartCPUProfile(f) 65 if err != nil { 66 return err 67 } 68 defer pprof.StopCPUProfile() 69 } 70 71 // HTTP profiler 72 if opts.HTTPProfile { 73 log.Warnf("Starting the HTTP profiler on path /debug/pprof/.") 74 // http pprof uses http.DefaultServeMux 75 http.Handle("/", http.RedirectHandler("/debug/pprof/", http.StatusSeeOther)) 76 go func() { 77 if err := http.ListenAndServe(":9232", nil); err != nil { 78 log.Errorf("ListenAndServe failed for http/pprof: %v", err) 79 } 80 }() 81 } 82 83 // Display app version. 84 log.Infof("%s version %v (Go version %s)", appName, Version, runtime.Version()) 85 log.Infof("dcrdex starting for network: %s", cfg.Network) 86 log.Infof("swap locktimes config: maker %s, taker %s", 87 dex.LockTimeMaker(cfg.Network), dex.LockTimeTaker(cfg.Network)) 88 89 // Load the market and asset configurations for the given network. 90 markets, assets, err := dexsrv.LoadConfig(cfg.Network, cfg.MarketsConfPath) 91 if err != nil { 92 return fmt.Errorf("failed to load market and asset config %q: %v", 93 cfg.MarketsConfPath, err) 94 } 95 log.Infof("Found %d assets, loaded %d markets, for network %s", 96 len(assets), len(markets), strings.ToUpper(cfg.Network.String())) 97 // NOTE: If MaxUserCancelsPerEpoch is ultimately a setting we want to keep, 98 // bake it into the markets.json file and load it per-market in settings.go. 99 // For now, patch it into each dex.MarketInfo. 100 for _, mkt := range markets { 101 mkt.MaxUserCancelsPerEpoch = cfg.MaxUserCancels 102 } 103 104 // Load, or create and save, the DEX signing key. 105 var privKey *secp256k1.PrivateKey 106 if len(cfg.SigningKeyPW) == 0 { 107 cfg.SigningKeyPW, err = admin.PasswordPrompt(ctx, "Signing key password: ") 108 if err != nil { 109 return fmt.Errorf("cannot use password: %v", err) 110 } 111 } 112 privKey, err = dexKey(cfg.DEXPrivKeyPath, cfg.SigningKeyPW) 113 encode.ClearBytes(cfg.SigningKeyPW) 114 if err != nil { 115 return err 116 } 117 118 // Create the DEX manager. 119 dexConf := &dexsrv.DexConf{ 120 DataDir: cfg.DataDir, 121 LogBackend: cfg.LogMaker, 122 Markets: markets, 123 Assets: assets, 124 Network: cfg.Network, 125 DBConf: &dexsrv.DBConf{ 126 DBName: cfg.DBName, 127 Host: cfg.DBHost, 128 User: cfg.DBUser, 129 Port: cfg.DBPort, 130 Pass: cfg.DBPass, 131 ShowPGConfig: cfg.ShowPGConfig, 132 }, 133 BroadcastTimeout: cfg.BroadcastTimeout, 134 TxWaitExpiration: cfg.TxWaitExpiration, 135 CancelThreshold: cfg.CancelThreshold, 136 FreeCancels: cfg.FreeCancels, 137 PenaltyThreshold: cfg.PenaltyThreshold, 138 DEXPrivKey: privKey, 139 CommsCfg: &dexsrv.RPCConfig{ 140 RPCCert: cfg.RPCCert, 141 NoTLS: cfg.NoTLS, 142 RPCKey: cfg.RPCKey, 143 ListenAddrs: cfg.RPCListen, 144 AltDNSNames: cfg.AltDNSNames, 145 DisableDataAPI: cfg.DisableDataAPI, 146 HiddenServiceAddr: cfg.HiddenService, 147 }, 148 NoResumeSwaps: cfg.NoResumeSwaps, 149 NodeRelayAddr: cfg.NodeRelayAddr, 150 } 151 dexMan, err := dexsrv.NewDEX(ctx, dexConf) // ctx cancel just aborts setup; Stop does normal shutdown 152 if err != nil { 153 return err 154 } 155 156 var wg sync.WaitGroup 157 if cfg.AdminSrvOn { 158 srvCFG := &admin.SrvConfig{ 159 Core: dexMan, 160 Addr: cfg.AdminSrvAddr, 161 AuthSHA: adminSrvAuthSHA, 162 Cert: cfg.RPCCert, 163 Key: cfg.RPCKey, 164 NoTLS: cfg.AdminSrvNoTLS, 165 } 166 adminServer, err := admin.NewServer(srvCFG) 167 if err != nil { 168 return fmt.Errorf("cannot set up admin server: %v", err) 169 } 170 wg.Add(1) 171 go func() { 172 adminServer.Run(ctx) 173 wg.Done() 174 }() 175 } 176 177 log.Info("The DEX is running. Hit CTRL+C to quit...") 178 <-ctx.Done() 179 // Wait for the admin server to finish. 180 wg.Wait() 181 182 log.Info("Stopping DEX...") 183 dexMan.Stop() 184 log.Info("Bye!") 185 186 return nil 187 } 188 189 func main() { 190 // Create a context that is canceled when a shutdown request is received 191 // via requestShutdown. 192 ctx := withShutdownCancel(context.Background()) 193 // Listen for both interrupt signals (e.g. CTRL+C) and shutdown requests 194 // (requestShutdown calls). 195 go shutdownListener() 196 197 err := mainCore(ctx) 198 if err != nil { 199 fmt.Fprintln(os.Stderr, err) 200 os.Exit(1) 201 } 202 os.Exit(0) 203 }