github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/cmd/smc/main.go (about)

     1  // Copyright 2014 The Spectrum Authors
     2  // This file is part of Spectrum.
     3  //
     4  // Spectrum is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // Spectrum is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU General Public License
    15  // along with Spectrum. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package main
    18  
    19  import (
    20  	"fmt"
    21  	"os"
    22  	"runtime"
    23  	"sort"
    24  	"strings"
    25  	"time"
    26  
    27  	"github.com/SmartMeshFoundation/Spectrum/accounts"
    28  	"github.com/SmartMeshFoundation/Spectrum/accounts/keystore"
    29  	"github.com/SmartMeshFoundation/Spectrum/cmd/utils"
    30  	"github.com/SmartMeshFoundation/Spectrum/console"
    31  	"github.com/SmartMeshFoundation/Spectrum/eth"
    32  	"github.com/SmartMeshFoundation/Spectrum/ethclient"
    33  	"github.com/SmartMeshFoundation/Spectrum/internal/debug"
    34  	"github.com/SmartMeshFoundation/Spectrum/log"
    35  	"github.com/SmartMeshFoundation/Spectrum/metrics"
    36  	"github.com/SmartMeshFoundation/Spectrum/node"
    37  	"gopkg.in/urfave/cli.v1"
    38  )
    39  
    40  const (
    41  	clientIdentifier = "smc" // Client identifier to advertise over the network
    42  )
    43  
    44  var (
    45  	// Git SHA1 commit hash of the release (set via linker flags)
    46  	gitCommit = ""
    47  	// Ethereum address of the Geth release oracle.
    48  	// relOracle = common.HexToAddress("0xfa7b9770ca4cb04296cac84f37736d4041251cdf")
    49  	// The app that holds all commands and flags.
    50  	app = utils.NewApp(gitCommit, "the Spectrum command line interface")
    51  	// flags that configure the node
    52  	nodeFlags = []cli.Flag{
    53  		utils.IdentityFlag,
    54  		utils.UnlockedAccountFlag,
    55  		utils.PasswordFileFlag,
    56  		utils.BootnodesFlag,
    57  		//utils.BootnodesV4Flag,
    58  		//utils.BootnodesV5Flag,
    59  		utils.DataDirFlag,
    60  		utils.KeyStoreDirFlag,
    61  		/*
    62  			utils.EthashCacheDirFlag,
    63  			utils.EthashCachesInMemoryFlag,
    64  			utils.EthashCachesOnDiskFlag,
    65  			utils.EthashDatasetDirFlag,
    66  			utils.EthashDatasetsInMemoryFlag,
    67  			utils.EthashDatasetsOnDiskFlag,
    68  		*/
    69  		utils.TxPoolNoLocalsFlag,
    70  		utils.TxPoolJournalFlag,
    71  		utils.TxPoolRejournalFlag,
    72  		utils.TxPoolPriceLimitFlag,
    73  		utils.TxPoolPriceBumpFlag,
    74  		utils.TxPoolAccountSlotsFlag,
    75  		utils.TxPoolGlobalSlotsFlag,
    76  		utils.TxPoolAccountQueueFlag,
    77  		utils.TxPoolGlobalQueueFlag,
    78  		utils.TxPoolLifetimeFlag,
    79  		/* add by liangc : disable
    80  		utils.FastSyncFlag,
    81  		utils.LightModeFlag,
    82  		utils.SyncModeFlag,
    83  
    84  		utils.LightServFlag,
    85  		utils.LightPeersFlag,
    86  		utils.LightKDFFlag,
    87  
    88  
    89  		utils.DashboardEnabledFlag,
    90  		utils.DashboardAddrFlag,
    91  		utils.DashboardPortFlag,
    92  		utils.DashboardRefreshFlag,
    93  		utils.DashboardAssetsFlag,
    94  
    95  		utils.NoUSBFlag,
    96  
    97  		utils.NodeKeyFileFlag,
    98  		utils.NodeKeyHexFlag,
    99  
   100  		utils.MinerThreadsFlag,
   101  		utils.MiningEnabledFlag,
   102  
   103  		utils.DiscoveryV5Flag,
   104  
   105  		utils.FakePoWFlag,
   106  		utils.DeveloperPeriodFlag,
   107  		utils.EtherbaseFlag,
   108  		*/
   109  		utils.CacheFlag,
   110  		utils.TrieCacheGenFlag,
   111  		utils.ListenPortFlag,
   112  		utils.MaxPeersFlag,
   113  		utils.MaxPendingPeersFlag,
   114  		utils.GasPriceFlag,
   115  		utils.TargetGasLimitFlag,
   116  		utils.NATFlag,
   117  		utils.NoDiscoverFlag,
   118  		utils.NetrestrictFlag,
   119  		//utils.DeveloperFlag,
   120  		utils.DevnetFlag,
   121  		utils.DevnetResetFlag,
   122  		utils.DevnetMasterFlag,
   123  		utils.TestnetFlag,
   124  		utils.VMEnableDebugFlag,
   125  		utils.NetworkIdFlag,
   126  		utils.RPCCORSDomainFlag,
   127  		utils.EthStatsURLFlag,
   128  		utils.MetricsEnabledFlag,
   129  		utils.NoCompactionFlag,
   130  		utils.GpoBlocksFlag,
   131  		utils.GpoPercentileFlag,
   132  		utils.ExtraDataFlag,
   133  		configFileFlag,
   134  	}
   135  
   136  	rpcFlags = []cli.Flag{
   137  		utils.RPCEnabledFlag,
   138  		utils.RPCListenAddrFlag,
   139  		utils.RPCPortFlag,
   140  		utils.RPCApiFlag,
   141  		utils.WSEnabledFlag,
   142  		utils.WSListenAddrFlag,
   143  		utils.WSPortFlag,
   144  		utils.WSApiFlag,
   145  		utils.WSAllowedOriginsFlag,
   146  		utils.IPCDisabledFlag,
   147  		utils.IPCPathFlag,
   148  	}
   149  
   150  	whisperFlags = []cli.Flag{
   151  		utils.WhisperEnabledFlag,
   152  		utils.WhisperMaxMessageSizeFlag,
   153  		utils.WhisperMinPOWFlag,
   154  	}
   155  )
   156  
   157  func init() {
   158  	// Initialize the CLI app and start Geth
   159  	app.Action = smc
   160  	app.HideVersion = true // we have a command to print the version
   161  	app.Copyright = "Copyright 2017-2018 The Spectrum Author"
   162  	app.Commands = []cli.Command{
   163  		// See chaincmd.go:
   164  		initCommand,
   165  		importCommand,
   166  		exportCommand,
   167  		copydbCommand,
   168  		removedbCommand,
   169  		dumpCommand,
   170  		// See monitorcmd.go:
   171  		//monitorCommand,
   172  		// See accountcmd.go:
   173  		accountCommand,
   174  		walletCommand,
   175  		// See consolecmd.go:
   176  		consoleCommand,
   177  		attachCommand,
   178  		javascriptCommand,
   179  		// See misccmd.go:
   180  		//makecacheCommand,
   181  		//makedagCommand,
   182  		versionCommand,
   183  		bugCommand,
   184  		licenseCommand,
   185  		// See config.go
   186  		dumpConfigCommand,
   187  		// add by liangc
   188  		securityCommand,
   189  	}
   190  	sort.Sort(cli.CommandsByName(app.Commands))
   191  
   192  	app.Flags = append(app.Flags, nodeFlags...)
   193  	app.Flags = append(app.Flags, rpcFlags...)
   194  	app.Flags = append(app.Flags, consoleFlags...)
   195  	app.Flags = append(app.Flags, debug.Flags...)
   196  	//app.Flags = append(app.Flags, whisperFlags...)
   197  
   198  	app.Before = func(ctx *cli.Context) error {
   199  		// add by liangc : append testnet flag
   200  		if tn := ctx.GlobalBool(utils.TestnetFlag.Name); tn {
   201  			fmt.Println("Testnet started.")
   202  			os.Setenv("TESTNET", "1")
   203  		}
   204  		if tn := ctx.GlobalBool(utils.DevnetFlag.Name); tn {
   205  			fmt.Println("Devnet started.")
   206  			os.Setenv("DEVNET", "1")
   207  		}
   208  		ipc := node.DefaultIPCEndpoint(clientIdentifier)
   209  
   210  		if dir := ctx.GlobalString(utils.DataDirFlag.Name); ctx.GlobalIsSet(utils.DataDirFlag.Name) {
   211  			ipc = node.DefaultIPCEndpointWithDir(dir, clientIdentifier)
   212  		}
   213  		os.Setenv("IPCPATH", ipc)
   214  
   215  		runtime.GOMAXPROCS(runtime.NumCPU())
   216  		if err := debug.Setup(ctx); err != nil {
   217  			return err
   218  		}
   219  		// Start system runtime metrics collection
   220  		go metrics.CollectProcessMetrics(3 * time.Second)
   221  
   222  		utils.SetupNetwork(ctx)
   223  		return nil
   224  	}
   225  
   226  	app.After = func(ctx *cli.Context) error {
   227  		debug.Exit()
   228  		console.Stdin.Close() // Resets terminal mode.
   229  		return nil
   230  	}
   231  }
   232  
   233  func main() {
   234  	if err := app.Run(os.Args); err != nil {
   235  		fmt.Fprintln(os.Stderr, err)
   236  		os.Exit(1)
   237  	}
   238  }
   239  
   240  func smc(ctx *cli.Context) error {
   241  	node := makeFullNode(ctx)
   242  	startNode(ctx, node)
   243  	node.Wait()
   244  	return nil
   245  }
   246  
   247  // startNode boots up the system node and all registered protocols, after which
   248  // it unlocks any requested accounts, and starts the RPC/IPC interfaces and the
   249  // miner.
   250  func startNode(ctx *cli.Context, stack *node.Node) {
   251  	// Start up the node itself
   252  	utils.StartNode(stack)
   253  	// Unlock any account specifically requested
   254  	ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
   255  
   256  	passwords := utils.MakePasswordList(ctx)
   257  	unlocks := strings.Split(ctx.GlobalString(utils.UnlockedAccountFlag.Name), ",")
   258  	for i, account := range unlocks {
   259  		if trimmed := strings.TrimSpace(account); trimmed != "" {
   260  			unlockAccount(ctx, ks, trimmed, i, passwords)
   261  		}
   262  	}
   263  	// Register wallet event handlers to open and auto-derive wallets
   264  	events := make(chan accounts.WalletEvent, 16)
   265  	stack.AccountManager().Subscribe(events)
   266  
   267  	go func() {
   268  		// Create an chain state reader for self-derivation
   269  		rpcClient, err := stack.Attach()
   270  		if err != nil {
   271  			utils.Fatalf("Failed to attach to self: %v", err)
   272  		}
   273  		stateReader := ethclient.NewClient(rpcClient)
   274  
   275  		// Open any wallets already attached
   276  		for _, wallet := range stack.AccountManager().Wallets() {
   277  			if err := wallet.Open(""); err != nil {
   278  				log.Warn("Failed to open wallet", "url", wallet.URL(), "err", err)
   279  			}
   280  		}
   281  		// Listen for wallet event till termination
   282  		for event := range events {
   283  			switch event.Kind {
   284  			case accounts.WalletArrived:
   285  				if err := event.Wallet.Open(""); err != nil {
   286  					log.Warn("New wallet appeared, failed to open", "url", event.Wallet.URL(), "err", err)
   287  				}
   288  			case accounts.WalletOpened:
   289  				status, _ := event.Wallet.Status()
   290  				log.Info("New wallet appeared", "url", event.Wallet.URL(), "status", status)
   291  
   292  				if event.Wallet.URL().Scheme == "ledger" {
   293  					event.Wallet.SelfDerive(accounts.DefaultLedgerBaseDerivationPath, stateReader)
   294  				} else {
   295  					event.Wallet.SelfDerive(accounts.DefaultBaseDerivationPath, stateReader)
   296  				}
   297  
   298  			case accounts.WalletDropped:
   299  				log.Info("Old wallet dropped", "url", event.Wallet.URL())
   300  				event.Wallet.Close()
   301  			}
   302  		}
   303  	}()
   304  	// Start auxiliary services if enabled
   305  	if ctx.GlobalBool(utils.MiningEnabledFlag.Name) || ctx.GlobalBool(utils.DeveloperFlag.Name) {
   306  		// Mining only makes sense if a full Ethereum node is running
   307  		var ethereum *eth.Ethereum
   308  		if err := stack.Service(&ethereum); err != nil {
   309  			utils.Fatalf("ethereum service not running: %v", err)
   310  		}
   311  		// Use a reduced number of threads if requested
   312  		if threads := ctx.GlobalInt(utils.MinerThreadsFlag.Name); threads > 0 {
   313  			type threaded interface {
   314  				SetThreads(threads int)
   315  			}
   316  			if th, ok := ethereum.Engine().(threaded); ok {
   317  				th.SetThreads(threads)
   318  			}
   319  		}
   320  		// Set the gas price to the limits from the CLI and start mining
   321  		ethereum.TxPool().SetGasPrice(utils.GlobalBig(ctx, utils.GasPriceFlag.Name))
   322  		if err := ethereum.StartMining(true); err != nil {
   323  			utils.Fatalf("Failed to start mining: %v", err)
   324  		}
   325  	}
   326  }