github.com/turingchain2020/turingchain@v1.1.21/util/cli/turingchain.go (about)

     1  // Copyright Turing Corp. 2018 All Rights Reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // +build go1.8
     6  
     7  // package cli RunTuringchain函数会加载各个模块,组合成区块链程序
     8  //主循环由消息队列驱动。
     9  //消息队列本身可插拔,可以支持各种队列
    10  //同时共识模式也是可以插拔的。
    11  //rpc 服务也是可以插拔的
    12  
    13  package cli
    14  
    15  import (
    16  	"flag"
    17  	"fmt"
    18  	"net/http"
    19  	_ "net/http/pprof" //
    20  	"os"
    21  	"path/filepath"
    22  	"runtime"
    23  
    24  	"github.com/turingchain2020/turingchain/common/crypto"
    25  
    26  	"github.com/turingchain2020/turingchain/p2p"
    27  
    28  	"github.com/turingchain2020/turingchain/metrics"
    29  
    30  	"time"
    31  
    32  	"github.com/turingchain2020/turingchain/blockchain"
    33  	"github.com/turingchain2020/turingchain/util"
    34  
    35  	"github.com/turingchain2020/turingchain/common"
    36  	"github.com/turingchain2020/turingchain/common/limits"
    37  	clog "github.com/turingchain2020/turingchain/common/log"
    38  	log "github.com/turingchain2020/turingchain/common/log/log15"
    39  	"github.com/turingchain2020/turingchain/common/version"
    40  	"github.com/turingchain2020/turingchain/consensus"
    41  	"github.com/turingchain2020/turingchain/executor"
    42  	"github.com/turingchain2020/turingchain/mempool"
    43  	"github.com/turingchain2020/turingchain/queue"
    44  	"github.com/turingchain2020/turingchain/rpc"
    45  	"github.com/turingchain2020/turingchain/store"
    46  	"github.com/turingchain2020/turingchain/types"
    47  	"github.com/turingchain2020/turingchain/wallet"
    48  	"google.golang.org/grpc/grpclog"
    49  )
    50  
    51  var (
    52  	cpuNum      = runtime.NumCPU()
    53  	configPath  = flag.String("f", "", "configfile")
    54  	datadir     = flag.String("datadir", "", "data dir of turingchain, include logs and datas")
    55  	versionCmd  = flag.Bool("v", false, "version")
    56  	fixtime     = flag.Bool("fixtime", false, "fix time")
    57  	waitPid     = flag.Bool("waitpid", false, "p2p stuck until seed save info wallet & wallet unlock")
    58  	rollback    = flag.Int64("rollback", 0, "rollback block. WARNNING this command is only for test")
    59  	save        = flag.Bool("save", false, "rollback save temporary block")
    60  	importFile  = flag.String("import", "", "import block file name")
    61  	exportTitle = flag.String("export", "", "export block title name")
    62  	fileDir     = flag.String("filedir", "", "import/export block file dir,defalut current path")
    63  	startHeight = flag.Int64("startheight", 0, "export block start height")
    64  )
    65  
    66  //RunTuringchain : run Turingchain
    67  func RunTuringchain(name, defCfg string) {
    68  	flag.Parse()
    69  	if *versionCmd {
    70  		fmt.Println(version.GetVersion())
    71  		return
    72  	}
    73  	if *configPath == "" {
    74  		if name == "" {
    75  			*configPath = "turingchain.toml"
    76  		} else {
    77  			*configPath = name + ".toml"
    78  		}
    79  	}
    80  	d, err := os.Getwd()
    81  	if err != nil {
    82  		panic(err)
    83  	}
    84  	log.Info("current dir:", "dir", d)
    85  	err = os.Chdir(pwd())
    86  	if err != nil {
    87  		panic(err)
    88  	}
    89  	d, err = os.Getwd()
    90  	if err != nil {
    91  		panic(err)
    92  	}
    93  	log.Info("current dir:", "dir", d)
    94  	err = limits.SetLimits()
    95  	if err != nil {
    96  		panic(err)
    97  	}
    98  	//set config: turingchaincoin 用 turingchaincoin.toml 这个配置文件
    99  	turingchainCfg := types.NewTuringchainConfig(types.MergeCfg(types.ReadFile(*configPath), defCfg))
   100  	cfg := turingchainCfg.GetModuleConfig()
   101  	if *datadir != "" {
   102  		util.ResetDatadir(cfg, *datadir)
   103  	}
   104  	if *fixtime {
   105  		cfg.FixTime = *fixtime
   106  	}
   107  	if *waitPid {
   108  		cfg.P2P.WaitPid = *waitPid
   109  	}
   110  
   111  	if len(cfg.NtpHosts) <= 0 {
   112  		cfg.NtpHosts = append(cfg.NtpHosts, types.NtpHosts...)
   113  	}
   114  	if cfg.FixTime {
   115  		go fixtimeRoutine(cfg.NtpHosts)
   116  	}
   117  	//compare minFee in wallet, mempool, exec
   118  	//set file log
   119  	clog.SetFileLog(cfg.Log)
   120  	//set grpc log
   121  	f, err := createFile(cfg.P2P.GrpcLogFile)
   122  	if err != nil {
   123  		glogv2 := grpclog.NewLoggerV2(os.Stdout, os.Stdout, os.Stdout)
   124  		grpclog.SetLoggerV2(glogv2)
   125  	} else {
   126  		glogv2 := grpclog.NewLoggerV2WithVerbosity(f, f, f, 10)
   127  		grpclog.SetLoggerV2(glogv2)
   128  	}
   129  	//set watching
   130  	t := time.Tick(10 * time.Second)
   131  	go func() {
   132  		for range t {
   133  			watching()
   134  		}
   135  	}()
   136  	//set pprof
   137  	go func() {
   138  		if cfg.Pprof != nil {
   139  			err := http.ListenAndServe(cfg.Pprof.ListenAddr, nil)
   140  			if err != nil {
   141  				log.Info("ListenAndServe", "listen addr", cfg.Pprof.ListenAddr, "err", err)
   142  			}
   143  		} else {
   144  			err := http.ListenAndServe("localhost:6060", nil)
   145  			if err != nil {
   146  				log.Info("ListenAndServe", "listen addr localhost:6060 err", err)
   147  			}
   148  		}
   149  	}()
   150  	//set maxprocs
   151  	runtime.GOMAXPROCS(cpuNum)
   152  	//开始区块链模块加载
   153  	//channel, rabitmq 等
   154  	crypto.Init(turingchainCfg.GetModuleConfig().Crypto, turingchainCfg.GetSubConfig().Crypto)
   155  	version.SetLocalDBVersion(cfg.Store.LocalDBVersion)
   156  	version.SetStoreDBVersion(cfg.Store.StoreDBVersion)
   157  	version.SetAppVersion(cfg.Version)
   158  	log.Info(cfg.Title + "-app:" + version.GetAppVersion() + " turingchain:" + version.GetVersion() + " localdb:" + version.GetLocalDBVersion() + " statedb:" + version.GetStoreDBVersion())
   159  	log.Info("loading queue")
   160  	q := queue.New("channel")
   161  	q.SetConfig(turingchainCfg)
   162  
   163  	log.Info("loading mempool module")
   164  	mem := mempool.New(turingchainCfg)
   165  	mem.SetQueueClient(q.Client())
   166  
   167  	log.Info("loading execs module")
   168  	exec := executor.New(turingchainCfg)
   169  	exec.SetQueueClient(q.Client())
   170  
   171  	log.Info("loading blockchain module")
   172  	cfg.BlockChain.RollbackBlock = *rollback
   173  	cfg.BlockChain.RollbackSave = *save
   174  	chain := blockchain.New(turingchainCfg)
   175  	chain.SetQueueClient(q.Client())
   176  
   177  	log.Info("loading store module")
   178  	s := store.New(turingchainCfg)
   179  	s.SetQueueClient(q.Client())
   180  
   181  	chain.Upgrade()
   182  
   183  	log.Info("loading consensus module")
   184  	cs := consensus.New(turingchainCfg)
   185  	cs.SetQueueClient(q.Client())
   186  
   187  	//jsonrpc, grpc, channel 三种模式
   188  	rpcapi := rpc.New(turingchainCfg)
   189  	rpcapi.SetQueueClient(q.Client())
   190  
   191  	log.Info("loading wallet module")
   192  	walletm := wallet.New(turingchainCfg)
   193  	walletm.SetQueueClient(q.Client())
   194  
   195  	chain.Rollbackblock()
   196  	//导入/导出区块通过title
   197  	if *importFile != "" {
   198  		chain.ImportBlockProc(*importFile, *fileDir)
   199  	}
   200  	if *exportTitle != "" {
   201  		chain.ExportBlockProc(*exportTitle, *fileDir, *startHeight)
   202  	}
   203  	log.Info("loading p2p module")
   204  	var network queue.Module
   205  	if cfg.P2P.Enable {
   206  		network = p2p.NewP2PMgr(turingchainCfg)
   207  	} else {
   208  		network = &util.MockModule{Key: "p2p"}
   209  	}
   210  	network.SetQueueClient(q.Client())
   211  
   212  	health := util.NewHealthCheckServer(q.Client())
   213  	health.Start(cfg.Health)
   214  	metrics.StartMetrics(turingchainCfg)
   215  	defer func() {
   216  		//close all module,clean some resource
   217  		log.Info("begin close health module")
   218  		health.Close()
   219  		log.Info("begin close blockchain module")
   220  		chain.Close()
   221  		log.Info("begin close mempool module")
   222  		mem.Close()
   223  		log.Info("begin close P2P module")
   224  		network.Close()
   225  		log.Info("begin close execs module")
   226  		exec.Close()
   227  		log.Info("begin close store module")
   228  		s.Close()
   229  		log.Info("begin close consensus module")
   230  		cs.Close()
   231  		log.Info("begin close rpc module")
   232  		rpcapi.Close()
   233  		log.Info("begin close wallet module")
   234  		walletm.Close()
   235  		log.Info("begin close queue module")
   236  		q.Close()
   237  
   238  	}()
   239  	q.Start()
   240  }
   241  
   242  func createFile(filename string) (*os.File, error) {
   243  	f, err := os.OpenFile(filename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
   244  	if err != nil {
   245  		return nil, err
   246  	}
   247  	return f, nil
   248  }
   249  
   250  func watching() {
   251  	var m runtime.MemStats
   252  	runtime.ReadMemStats(&m)
   253  	log.Info("info:", "NumGoroutine:", runtime.NumGoroutine())
   254  	log.Info("info:", "Mem:", m.Sys/(1024*1024))
   255  	log.Info("info:", "HeapAlloc:", m.HeapAlloc/(1024*1024))
   256  }
   257  
   258  func pwd() string {
   259  	dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
   260  	if err != nil {
   261  		panic(err)
   262  	}
   263  	return dir
   264  }
   265  
   266  func fixtimeRoutine(hosts []string) {
   267  	for i := 0; i < len(hosts); i++ {
   268  		t, err := common.GetNtpTime(hosts[i])
   269  		if err == nil {
   270  			log.Info("time", "host", hosts[i], "now", t)
   271  		} else {
   272  			log.Error("time", "err", err)
   273  		}
   274  	}
   275  	t := common.GetRealTimeRetry(hosts, 10)
   276  	if !t.IsZero() {
   277  		//update
   278  		types.SetTimeDelta(int64(time.Until(t)))
   279  		log.Info("change time", "delta", time.Until(t), "real.now", types.Now())
   280  	}
   281  	//时间请求频繁一点:
   282  	ticket := time.NewTicker(time.Minute * 1)
   283  	for range ticket.C {
   284  		t = common.GetRealTimeRetry(hosts, 10)
   285  		if !t.IsZero() {
   286  			//update
   287  			log.Info("change time", "delta", time.Until(t))
   288  			types.SetTimeDelta(int64(time.Until(t)))
   289  		}
   290  	}
   291  }