2015-08-26 06:03:18 +02:00
|
|
|
// Copyright (c) 2013-2016 The btcsuite developers
|
2013-08-06 23:55:22 +02:00
|
|
|
// Use of this source code is governed by an ISC
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2013-11-20 16:35:14 +01:00
|
|
|
"fmt"
|
2013-08-06 23:55:22 +02:00
|
|
|
"net"
|
2013-09-17 23:40:27 +02:00
|
|
|
"net/http"
|
|
|
|
_ "net/http/pprof"
|
2013-08-06 23:55:22 +02:00
|
|
|
"os"
|
|
|
|
"runtime"
|
2016-05-05 21:16:58 +02:00
|
|
|
"runtime/debug"
|
2013-10-26 23:12:54 +02:00
|
|
|
"runtime/pprof"
|
2014-07-02 15:50:08 +02:00
|
|
|
|
2016-02-19 05:51:18 +01:00
|
|
|
"github.com/btcsuite/btcd/blockchain/indexers"
|
2015-01-17 07:48:13 +01:00
|
|
|
"github.com/btcsuite/btcd/limits"
|
2013-08-06 23:55:22 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2016-08-11 20:39:23 +02:00
|
|
|
cfg *config
|
2013-08-06 23:55:22 +02:00
|
|
|
)
|
|
|
|
|
2014-01-11 05:32:05 +01:00
|
|
|
// winServiceMain is only invoked on Windows. It detects when btcd is running
|
|
|
|
// as a service and reacts accordingly.
|
2013-11-26 03:58:18 +01:00
|
|
|
var winServiceMain func() (bool, error)
|
|
|
|
|
2013-08-06 23:55:22 +02:00
|
|
|
// btcdMain is the real main function for btcd. It is necessary to work around
|
2013-11-20 16:35:14 +01:00
|
|
|
// the fact that deferred functions do not run when os.Exit() is called. The
|
|
|
|
// optional serverChan parameter is mainly used by the service code to be
|
|
|
|
// notified with the server once it is setup so it can gracefully stop it when
|
|
|
|
// requested from the service control manager.
|
|
|
|
func btcdMain(serverChan chan<- *server) error {
|
2014-02-12 22:43:27 +01:00
|
|
|
// Load configuration and parse command line. This function also
|
|
|
|
// initializes logging and configures it accordingly.
|
2013-08-06 23:55:22 +02:00
|
|
|
tcfg, _, err := loadConfig()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
cfg = tcfg
|
2017-05-24 23:24:06 +02:00
|
|
|
defer func() {
|
|
|
|
if logRotator != nil {
|
|
|
|
logRotator.Close()
|
|
|
|
}
|
|
|
|
}()
|
2013-08-06 23:55:22 +02:00
|
|
|
|
2016-08-11 20:39:23 +02:00
|
|
|
// Get a channel that will be closed when a shutdown signal has been
|
|
|
|
// triggered either from an OS signal such as SIGINT (Ctrl+C) or from
|
|
|
|
// another subsystem such as the RPC server.
|
|
|
|
interruptedChan := interruptListener()
|
|
|
|
defer btcdLog.Info("Shutdown complete")
|
|
|
|
|
2013-10-15 22:54:00 +02:00
|
|
|
// Show version at startup.
|
2013-11-21 19:03:56 +01:00
|
|
|
btcdLog.Infof("Version %s", version())
|
2013-10-15 22:54:00 +02:00
|
|
|
|
2013-10-26 23:12:54 +02:00
|
|
|
// Enable http profiling server if requested.
|
2013-09-17 23:40:27 +02:00
|
|
|
if cfg.Profile != "" {
|
|
|
|
go func() {
|
2013-09-18 00:15:49 +02:00
|
|
|
listenAddr := net.JoinHostPort("", cfg.Profile)
|
2013-11-21 19:03:56 +01:00
|
|
|
btcdLog.Infof("Profile server listening on %s", listenAddr)
|
2013-10-23 17:48:17 +02:00
|
|
|
profileRedirect := http.RedirectHandler("/debug/pprof",
|
|
|
|
http.StatusSeeOther)
|
|
|
|
http.Handle("/", profileRedirect)
|
2013-11-21 19:03:56 +01:00
|
|
|
btcdLog.Errorf("%v", http.ListenAndServe(listenAddr, nil))
|
2013-09-17 23:40:27 +02:00
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
2013-10-26 23:12:54 +02:00
|
|
|
// Write cpu profile if requested.
|
2014-07-02 16:25:42 +02:00
|
|
|
if cfg.CPUProfile != "" {
|
|
|
|
f, err := os.Create(cfg.CPUProfile)
|
2013-10-26 23:12:54 +02:00
|
|
|
if err != nil {
|
2013-11-21 19:03:56 +01:00
|
|
|
btcdLog.Errorf("Unable to create cpu profile: %v", err)
|
2013-10-26 23:12:54 +02:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
pprof.StartCPUProfile(f)
|
2014-01-29 01:53:25 +01:00
|
|
|
defer f.Close()
|
2013-10-26 23:12:54 +02:00
|
|
|
defer pprof.StopCPUProfile()
|
|
|
|
}
|
|
|
|
|
2013-09-15 20:39:28 +02:00
|
|
|
// Perform upgrades to btcd as new versions require it.
|
2013-10-08 02:24:44 +02:00
|
|
|
if err := doUpgrades(); err != nil {
|
2013-11-21 19:03:56 +01:00
|
|
|
btcdLog.Errorf("%v", err)
|
2013-09-15 20:39:28 +02:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2016-08-11 20:39:23 +02:00
|
|
|
// Return now if an interrupt signal was triggered.
|
|
|
|
if interruptRequested(interruptedChan) {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2013-08-06 23:55:22 +02:00
|
|
|
// Load the block database.
|
|
|
|
db, err := loadBlockDB()
|
|
|
|
if err != nil {
|
2013-11-21 19:03:56 +01:00
|
|
|
btcdLog.Errorf("%v", err)
|
2013-08-06 23:55:22 +02:00
|
|
|
return err
|
|
|
|
}
|
2016-08-11 20:39:23 +02:00
|
|
|
defer func() {
|
|
|
|
// Ensure the database is sync'd and closed on shutdown.
|
2013-11-21 19:03:56 +01:00
|
|
|
btcdLog.Infof("Gracefully shutting down the database...")
|
2015-08-26 06:03:18 +02:00
|
|
|
db.Close()
|
2016-08-11 20:39:23 +02:00
|
|
|
}()
|
|
|
|
|
|
|
|
// Return now if an interrupt signal was triggered.
|
|
|
|
if interruptRequested(interruptedChan) {
|
|
|
|
return nil
|
|
|
|
}
|
2013-08-06 23:55:22 +02:00
|
|
|
|
2016-02-19 05:51:18 +01:00
|
|
|
// Drop indexes and exit if requested.
|
|
|
|
//
|
|
|
|
// NOTE: The order is important here because dropping the tx index also
|
|
|
|
// drops the address index since it relies on it.
|
|
|
|
if cfg.DropAddrIndex {
|
|
|
|
if err := indexers.DropAddrIndex(db); err != nil {
|
|
|
|
btcdLog.Errorf("%v", err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
if cfg.DropTxIndex {
|
|
|
|
if err := indexers.DropTxIndex(db); err != nil {
|
|
|
|
btcdLog.Errorf("%v", err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2013-08-06 23:55:22 +02:00
|
|
|
// Create server and start it.
|
2014-05-23 06:14:36 +02:00
|
|
|
server, err := newServer(cfg.Listeners, db, activeNetParams.Params)
|
2013-08-06 23:55:22 +02:00
|
|
|
if err != nil {
|
2016-11-16 00:43:43 +01:00
|
|
|
// TODO: this logging could do with some beautifying.
|
2013-11-21 19:03:56 +01:00
|
|
|
btcdLog.Errorf("Unable to start server on %v: %v",
|
2013-09-19 17:46:33 +02:00
|
|
|
cfg.Listeners, err)
|
2013-08-06 23:55:22 +02:00
|
|
|
return err
|
|
|
|
}
|
2016-08-11 20:39:23 +02:00
|
|
|
defer func() {
|
2013-12-10 19:21:34 +01:00
|
|
|
btcdLog.Infof("Gracefully shutting down the server...")
|
|
|
|
server.Stop()
|
|
|
|
server.WaitForShutdown()
|
2016-08-11 20:39:23 +02:00
|
|
|
srvrLog.Infof("Server shutdown complete")
|
|
|
|
}()
|
2013-08-06 23:55:22 +02:00
|
|
|
server.Start()
|
2013-11-20 16:35:14 +01:00
|
|
|
if serverChan != nil {
|
|
|
|
serverChan <- server
|
|
|
|
}
|
2013-08-06 23:55:22 +02:00
|
|
|
|
2016-08-11 20:39:23 +02:00
|
|
|
// Wait until the interrupt signal is received from an OS signal or
|
|
|
|
// shutdown is requested through one of the subsystems such as the RPC
|
|
|
|
// server.
|
|
|
|
<-interruptedChan
|
2013-08-06 23:55:22 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
// Use all processor cores.
|
|
|
|
runtime.GOMAXPROCS(runtime.NumCPU())
|
|
|
|
|
2016-05-05 21:16:58 +02:00
|
|
|
// Block and transaction processing can cause bursty allocations. This
|
|
|
|
// limits the garbage collector from excessively overallocating during
|
|
|
|
// bursts. This value was arrived at with the help of profiling live
|
|
|
|
// usage.
|
|
|
|
debug.SetGCPercent(10)
|
|
|
|
|
2013-10-07 23:24:19 +02:00
|
|
|
// Up some limits.
|
2014-01-07 22:30:25 +01:00
|
|
|
if err := limits.SetLimits(); err != nil {
|
2015-09-03 00:13:01 +02:00
|
|
|
fmt.Fprintf(os.Stderr, "failed to set limits: %v\n", err)
|
2013-10-07 23:24:19 +02:00
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
|
2013-11-20 16:35:14 +01:00
|
|
|
// Call serviceMain on Windows to handle running as a service. When
|
|
|
|
// the return isService flag is true, exit now since we ran as a
|
|
|
|
// service. Otherwise, just fall through to normal operation.
|
|
|
|
if runtime.GOOS == "windows" {
|
2013-11-26 03:58:18 +01:00
|
|
|
isService, err := winServiceMain()
|
2013-11-20 16:35:14 +01:00
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err)
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
if isService {
|
|
|
|
os.Exit(0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-06 23:55:22 +02:00
|
|
|
// Work around defer not working after os.Exit()
|
2013-11-20 16:35:14 +01:00
|
|
|
if err := btcdMain(nil); err != nil {
|
2013-08-06 23:55:22 +02:00
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
}
|