github.com/bigzoro/my_simplechain@v0.0.0-20240315012955-8ad0a2a29bb9/cmd/sipe/main.go (about)

     1  // Copyright 2014 The go-simplechain Authors
     2  // This file is part of go-simplechain.
     3  //
     4  // go-simplechain 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  // go-simplechain 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 go-simplechain. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // geth is the official command-line client for SimpleService.
    18  package main
    19  
    20  import (
    21  	"fmt"
    22  	"math"
    23  	"os"
    24  	"runtime"
    25  	godebug "runtime/debug"
    26  	"sort"
    27  	"strconv"
    28  	"strings"
    29  	"time"
    30  
    31  	"github.com/bigzoro/my_simplechain/accounts"
    32  	"github.com/bigzoro/my_simplechain/accounts/keystore"
    33  	"github.com/bigzoro/my_simplechain/cmd/utils"
    34  	"github.com/bigzoro/my_simplechain/common"
    35  	"github.com/bigzoro/my_simplechain/consensus/raft/backend"
    36  	"github.com/bigzoro/my_simplechain/console"
    37  	"github.com/bigzoro/my_simplechain/eth"
    38  	"github.com/bigzoro/my_simplechain/eth/downloader"
    39  	"github.com/bigzoro/my_simplechain/ethclient"
    40  	"github.com/bigzoro/my_simplechain/internal/debug"
    41  	"github.com/bigzoro/my_simplechain/les"
    42  	"github.com/bigzoro/my_simplechain/log"
    43  	"github.com/bigzoro/my_simplechain/metrics"
    44  	"github.com/bigzoro/my_simplechain/miner"
    45  	"github.com/bigzoro/my_simplechain/node"
    46  	"github.com/bigzoro/my_simplechain/permission"
    47  
    48  	"github.com/elastic/gosigar"
    49  	cli "gopkg.in/urfave/cli.v1"
    50  )
    51  
    52  const (
    53  	clientIdentifier = "sipe" // Client identifier to advertise over the network
    54  )
    55  
    56  var (
    57  	// Git SHA1 commit hash of the release (set via linker flags)
    58  	gitCommit = ""
    59  	gitDate   = ""
    60  	// The app that holds all commands and flags.
    61  	app = utils.NewApp(gitCommit, gitDate, "the go-simplechain command line interface")
    62  	// flags that configure the node
    63  	nodeFlags = []cli.Flag{
    64  		utils.IdentityFlag,
    65  		utils.UnlockedAccountFlag,
    66  		utils.PasswordFileFlag,
    67  		utils.BootnodesFlag,
    68  		utils.BootnodesV4Flag,
    69  		utils.BootnodesV5Flag,
    70  		utils.DataDirFlag,
    71  		utils.AncientFlag,
    72  		utils.KeyStoreDirFlag,
    73  		utils.ExternalSignerFlag,
    74  		utils.NoUSBFlag,
    75  		utils.SmartCardDaemonPathFlag,
    76  		utils.OverrideSingularityFlag,
    77  		utils.EthashCacheDirFlag,
    78  		utils.EthashCachesInMemoryFlag,
    79  		utils.EthashCachesOnDiskFlag,
    80  		utils.EthashDatasetDirFlag,
    81  		utils.EthashDatasetsInMemoryFlag,
    82  		utils.EthashDatasetsOnDiskFlag,
    83  		utils.TxPoolLocalsFlag,
    84  		utils.TxPoolNoLocalsFlag,
    85  		utils.TxPoolJournalFlag,
    86  		utils.TxPoolRejournalFlag,
    87  		utils.TxPoolPriceLimitFlag,
    88  		utils.TxPoolPriceBumpFlag,
    89  		utils.TxPoolAccountSlotsFlag,
    90  		utils.TxPoolGlobalSlotsFlag,
    91  		utils.TxPoolAccountQueueFlag,
    92  		utils.TxPoolGlobalQueueFlag,
    93  		utils.TxPoolLifetimeFlag,
    94  		utils.SyncModeFlag,
    95  		utils.ExitWhenSyncedFlag,
    96  		utils.GCModeFlag,
    97  		utils.LightServeFlag,
    98  		utils.LightIngressFlag,
    99  		utils.LightEgressFlag,
   100  		utils.LightMaxPeersFlag,
   101  		utils.LightKDFFlag,
   102  		utils.UltraLightServersFlag,
   103  		utils.UltraLightFractionFlag,
   104  		utils.UltraLightOnlyAnnounceFlag,
   105  		utils.WhitelistFlag,
   106  		utils.CacheFlag,
   107  		utils.CacheDatabaseFlag,
   108  		utils.CacheTrieFlag,
   109  		utils.CacheGCFlag,
   110  		utils.CacheNoPrefetchFlag,
   111  		utils.ListenPortFlag,
   112  		utils.MaxPeersFlag,
   113  		utils.MaxPendingPeersFlag,
   114  		utils.MiningEnabledFlag,
   115  		utils.MinerThreadsFlag,
   116  		utils.MinerNotifyFlag,
   117  		utils.MinerGasTargetFlag,
   118  		utils.MinerGasLimitFlag,
   119  		utils.MinerGasPriceFlag,
   120  		utils.MinerEtherbaseFlag,
   121  		utils.MinerExtraDataFlag,
   122  		utils.MinerRecommitIntervalFlag,
   123  		utils.MinerNoVerifyFlag,
   124  		utils.MinerNoEmptyBlockFlag,
   125  		utils.MinerTxLimitFlag,
   126  		utils.NATFlag,
   127  		utils.NoDiscoverFlag,
   128  		utils.DiscoveryV5Flag,
   129  		utils.NetrestrictFlag,
   130  		utils.NodeKeyFileFlag,
   131  		utils.NodeKeyHexFlag,
   132  		utils.DeveloperFlag,
   133  		utils.DeveloperPeriodFlag,
   134  		utils.TestnetFlag,
   135  		utils.VMEnableDebugFlag,
   136  		utils.NetworkIdFlag,
   137  		utils.EthStatsURLFlag,
   138  		utils.FakePoWFlag,
   139  		utils.NoCompactionFlag,
   140  		utils.GpoBlocksFlag,
   141  		utils.GpoPercentileFlag,
   142  		utils.EWASMInterpreterFlag,
   143  		utils.EVMInterpreterFlag,
   144  		// permission
   145  		utils.EnableNodePermissionFlag,
   146  		//raft
   147  		utils.RaftModeFlag,
   148  		utils.FirstRaftNodeFlag,
   149  		utils.RaftPortFlag,
   150  		//pbft
   151  		utils.PbftBlockPeriodFlag,
   152  		utils.PbftEnableLightFlag,
   153  		utils.PbftMaxBlockTxsSealFlag,
   154  		utils.PbftRequestTimeoutFlag,
   155  		//monitor
   156  		utils.MonitorPortFlag,
   157  		utils.MonitorModeFlag,
   158  		configFileFlag,
   159  		// hostuff
   160  		utils.HotstuffModeFlag,
   161  		utils.HotstuffSecretFlag,
   162  		utils.HotstuffIDFlag,
   163  	}
   164  
   165  	rpcFlags = []cli.Flag{
   166  		utils.APITLSEnabledFlag,
   167  		utils.PeerTLSEnabledFlag,
   168  		utils.PeerTLSDirFlag,
   169  		utils.RPCEnabledFlag,
   170  		utils.RPCListenAddrFlag,
   171  		utils.RPCPortFlag,
   172  		utils.RPCCORSDomainFlag,
   173  		utils.RPCVirtualHostsFlag,
   174  		utils.GraphQLEnabledFlag,
   175  		utils.GraphQLListenAddrFlag,
   176  		utils.GraphQLPortFlag,
   177  		utils.GraphQLCORSDomainFlag,
   178  		utils.GraphQLVirtualHostsFlag,
   179  		utils.RPCApiFlag,
   180  		utils.WSEnabledFlag,
   181  		utils.WSListenAddrFlag,
   182  		utils.WSPortFlag,
   183  		utils.WSApiFlag,
   184  		utils.WSAllowedOriginsFlag,
   185  		utils.IPCDisabledFlag,
   186  		utils.IPCPathFlag,
   187  		utils.InsecureUnlockAllowedFlag,
   188  		utils.RPCGlobalGasCap,
   189  	}
   190  	whisperFlags = []cli.Flag{
   191  		utils.WhisperEnabledFlag,
   192  		utils.WhisperMaxMessageSizeFlag,
   193  		utils.WhisperMinPOWFlag,
   194  		utils.WhisperRestrictConnectionBetweenLightClientsFlag,
   195  	}
   196  
   197  	metricsFlags = []cli.Flag{
   198  		utils.MetricsEnabledFlag,
   199  		utils.MetricsEnabledExpensiveFlag,
   200  		utils.MetricsEnableInfluxDBFlag,
   201  		utils.MetricsInfluxDBEndpointFlag,
   202  		utils.MetricsInfluxDBDatabaseFlag,
   203  		utils.MetricsInfluxDBUsernameFlag,
   204  		utils.MetricsInfluxDBPasswordFlag,
   205  		utils.MetricsInfluxDBTagsFlag,
   206  	}
   207  )
   208  
   209  func init() {
   210  	// Initialize the CLI app and start Geth
   211  	app.Action = sipe
   212  	app.HideVersion = true // we have a command to print the version
   213  	app.Copyright = "Copyright 2013-2019 The go-simplechain Authors"
   214  	app.Commands = []cli.Command{
   215  		// See chaincmd.go:
   216  		initCommand,
   217  		importCommand,
   218  		exportCommand,
   219  		importPreimagesCommand,
   220  		exportPreimagesCommand,
   221  		copydbCommand,
   222  		removedbCommand,
   223  		dumpCommand,
   224  		inspectCommand,
   225  		// See accountcmd.go:
   226  		accountCommand,
   227  		walletCommand,
   228  		// See consolecmd.go:
   229  		consoleCommand,
   230  		attachCommand,
   231  		javascriptCommand,
   232  		// See misccmd.go:
   233  		makecacheCommand,
   234  		makedagCommand,
   235  		versionCommand,
   236  		licenseCommand,
   237  		// See config.go
   238  		dumpConfigCommand,
   239  		// See retesteth.go
   240  		retestethCommand,
   241  		genScretKeyCommand,
   242  		aggregateCommand,
   243  	}
   244  	sort.Sort(cli.CommandsByName(app.Commands))
   245  
   246  	app.Flags = append(app.Flags, nodeFlags...)
   247  	app.Flags = append(app.Flags, rpcFlags...)
   248  	app.Flags = append(app.Flags, consoleFlags...)
   249  	app.Flags = append(app.Flags, debug.Flags...)
   250  	app.Flags = append(app.Flags, whisperFlags...)
   251  	app.Flags = append(app.Flags, metricsFlags...)
   252  	app.Before = func(ctx *cli.Context) error {
   253  		return debug.Setup(ctx, "")
   254  	}
   255  	app.After = func(ctx *cli.Context) error {
   256  		debug.Exit()
   257  		console.Stdin.Close() // Resets terminal mode.
   258  		return nil
   259  	}
   260  }
   261  
   262  func main() {
   263  	if err := app.Run(os.Args); err != nil {
   264  		fmt.Fprintln(os.Stderr, err)
   265  		os.Exit(1)
   266  	}
   267  }
   268  
   269  // prepare manipulates memory cache allowance and setups metric system.
   270  // This function should be called before launching devp2p stack.
   271  func prepare(ctx *cli.Context) {
   272  	// If we're a full node on mainnet without --cache specified, bump default cache allowance
   273  	if ctx.GlobalString(utils.SyncModeFlag.Name) != "light" && !ctx.GlobalIsSet(utils.CacheFlag.Name) && !ctx.GlobalIsSet(utils.NetworkIdFlag.Name) {
   274  		// Make sure we're not on any supported preconfigured testnet either
   275  		if !ctx.GlobalIsSet(utils.TestnetFlag.Name) && !ctx.GlobalIsSet(utils.DeveloperFlag.Name) {
   276  			// Nope, we're really on mainnet. Bump that cache up!
   277  			log.Info("Bumping default cache on mainnet", "provided", ctx.GlobalInt(utils.CacheFlag.Name), "updated", 4096)
   278  			ctx.GlobalSet(utils.CacheFlag.Name, strconv.Itoa(4096))
   279  		}
   280  	}
   281  	// If we're running a light client on any network, drop the cache to some meaningfully low amount
   282  	if ctx.GlobalString(utils.SyncModeFlag.Name) == "light" && !ctx.GlobalIsSet(utils.CacheFlag.Name) {
   283  		log.Info("Dropping default light client cache", "provided", ctx.GlobalInt(utils.CacheFlag.Name), "updated", 128)
   284  		ctx.GlobalSet(utils.CacheFlag.Name, strconv.Itoa(128))
   285  	}
   286  	// Cap the cache allowance and tune the garbage collector
   287  	var mem gosigar.Mem
   288  	// Workaround until OpenBSD support lands into gosigar
   289  	// Check https://github.com/elastic/gosigar#supported-platforms
   290  	if runtime.GOOS != "openbsd" {
   291  		if err := mem.Get(); err == nil {
   292  			allowance := int(mem.Total / 1024 / 1024 / 3)
   293  			if cache := ctx.GlobalInt(utils.CacheFlag.Name); cache > allowance {
   294  				log.Warn("Sanitizing cache to Go's GC limits", "provided", cache, "updated", allowance)
   295  				ctx.GlobalSet(utils.CacheFlag.Name, strconv.Itoa(allowance))
   296  			}
   297  		}
   298  	}
   299  	// Ensure Go's GC ignores the database cache for trigger percentage
   300  	cache := ctx.GlobalInt(utils.CacheFlag.Name)
   301  	gogc := math.Max(20, math.Min(100, 100/(float64(cache)/1024)))
   302  
   303  	log.Debug("Sanitizing Go's GC trigger", "percent", int(gogc))
   304  	godebug.SetGCPercent(int(gogc))
   305  
   306  	// Start metrics export if enabled
   307  	utils.SetupMetrics(ctx)
   308  
   309  	// Start system runtime metrics collection
   310  	go metrics.CollectProcessMetrics(3 * time.Second)
   311  }
   312  
   313  // geth is the main entry point into the system if no special subcommand is ran.
   314  // It creates a default node based on the command line arguments and runs it in
   315  // blocking mode, waiting for it to be shut down.
   316  func sipe(ctx *cli.Context) error {
   317  	if args := ctx.Args(); len(args) > 0 {
   318  		return fmt.Errorf("invalid command: %q", args[0])
   319  	}
   320  	prepare(ctx)
   321  	node := makeFullNode(ctx)
   322  	defer node.Close()
   323  	startNode(ctx, node)
   324  	node.Wait()
   325  	return nil
   326  }
   327  
   328  // startNode boots up the system node and all registered protocols, after which
   329  // it unlocks any requested accounts, and starts the RPC/IPC interfaces and the
   330  // miner.
   331  func startNode(ctx *cli.Context, stack *node.Node) {
   332  	debug.Memsize.Add("node", stack)
   333  
   334  	// Start up the node itself
   335  	utils.StartNode(stack)
   336  	// Unlock any account specifically requested
   337  	unlockAccounts(ctx, stack)
   338  
   339  	// Register wallet event handlers to open and auto-derive wallets
   340  	events := make(chan accounts.WalletEvent, 16)
   341  	stack.AccountManager().Subscribe(events)
   342  
   343  	// Create a client to interact with local geth node.
   344  	rpcClient, err := stack.Attach()
   345  	if err != nil {
   346  		utils.Fatalf("Failed to attach to self: %v", err)
   347  	}
   348  	ethClient := ethclient.NewClient(rpcClient)
   349  
   350  	// Set contract backend for ethereum service if local node
   351  	// is serving LES requests.
   352  	if ctx.GlobalInt(utils.LightServeFlag.Name) > 0 {
   353  		var ethService *eth.SimpleService
   354  		if err := stack.Service(&ethService); err != nil {
   355  			utils.Fatalf("Failed to retrieve ethereum service: %v", err)
   356  		}
   357  		ethService.SetContractBackend(ethClient)
   358  	}
   359  	// Set contract backend for les service if local node is
   360  	// running as a light client.
   361  	if ctx.GlobalString(utils.SyncModeFlag.Name) == "light" {
   362  		var lesService *les.LightEthereum
   363  		if err := stack.Service(&lesService); err != nil {
   364  			utils.Fatalf("Failed to retrieve light ethereum service: %v", err)
   365  		}
   366  		lesService.SetContractBackend(ethClient)
   367  	}
   368  	go func() {
   369  		// Open any wallets already attached
   370  		for _, wallet := range stack.AccountManager().Wallets() {
   371  			if err := wallet.Open(""); err != nil {
   372  				log.Warn("Failed to open wallet", "url", wallet.URL(), "err", err)
   373  			}
   374  		}
   375  		// Listen for wallet event till termination
   376  		for event := range events {
   377  			switch event.Kind {
   378  			case accounts.WalletArrived:
   379  				if err := event.Wallet.Open(""); err != nil {
   380  					log.Warn("New wallet appeared, failed to open", "url", event.Wallet.URL(), "err", err)
   381  				}
   382  			case accounts.WalletOpened:
   383  				status, _ := event.Wallet.Status()
   384  				log.Info("New wallet appeared", "url", event.Wallet.URL(), "status", status)
   385  
   386  				var derivationPaths []accounts.DerivationPath
   387  				if event.Wallet.URL().Scheme == "ledger" {
   388  					derivationPaths = append(derivationPaths, accounts.LegacyLedgerBaseDerivationPath)
   389  				}
   390  				derivationPaths = append(derivationPaths, accounts.DefaultBaseDerivationPath)
   391  
   392  				event.Wallet.SelfDerive(derivationPaths, ethClient)
   393  
   394  			case accounts.WalletDropped:
   395  				log.Info("Old wallet dropped", "url", event.Wallet.URL())
   396  				event.Wallet.Close()
   397  			}
   398  		}
   399  	}()
   400  
   401  	//get raft service
   402  	var rs *backend.RaftService
   403  	if ctx.GlobalBool(utils.RaftModeFlag.Name) {
   404  		if err := stack.Service(&rs); err != nil {
   405  			utils.Fatalf("Raft service not runnning: %v", err)
   406  		}
   407  	}
   408  	//checking if permissions is enabled and staring the permissions service
   409  	var permissionService *permission.Service
   410  	if err := stack.Service(&permissionService); err != nil {
   411  		utils.Fatalf("Permission service not runnning: %v", err)
   412  	}
   413  	if err := permissionService.Prepare(); err != nil {
   414  		utils.Fatalf("Permission service post construct failure: %v", err)
   415  	}
   416  	if ctx.GlobalBool(utils.RaftModeFlag.Name) {
   417  		permissionService.RaftProtocolManager = rs.RaftProtocolManager
   418  	}
   419  
   420  	// Spawn a standalone goroutine for status synchronization monitoring,
   421  	// close the node when synchronization is complete if user required.
   422  	if ctx.GlobalBool(utils.ExitWhenSyncedFlag.Name) {
   423  		go func() {
   424  			sub := stack.EventMux().Subscribe(downloader.DoneEvent{})
   425  			defer sub.Unsubscribe()
   426  			for {
   427  				event := <-sub.Chan()
   428  				if event == nil {
   429  					continue
   430  				}
   431  				done, ok := event.Data.(downloader.DoneEvent)
   432  				if !ok {
   433  					continue
   434  				}
   435  				if timestamp := time.Unix(int64(done.Latest.Time), 0); time.Since(timestamp) < 10*time.Minute {
   436  					log.Info("Synchronisation completed", "latestnum", done.Latest.Number, "latesthash", done.Latest.Hash(),
   437  						"age", common.PrettyAge(timestamp))
   438  					stack.Stop()
   439  				}
   440  			}
   441  		}()
   442  	}
   443  	// Start auxiliary services if enabled
   444  	if ctx.GlobalBool(utils.MiningEnabledFlag.Name) || ctx.GlobalBool(utils.DeveloperFlag.Name) {
   445  		// Mining only makes sense if a full SimpleService node is running
   446  		if ctx.GlobalString(utils.SyncModeFlag.Name) == "light" {
   447  			utils.Fatalf("Light clients do not support mining")
   448  		}
   449  		var ethereum *eth.SimpleService
   450  		if err := stack.Service(&ethereum); err != nil {
   451  			utils.Fatalf("SimpleService service not running: %v", err)
   452  		}
   453  		gasPrice := utils.GlobalBig(ctx, utils.MinerGasPriceFlag.Name)
   454  
   455  		ethereum.TxPool().SetGasPrice(gasPrice)
   456  
   457  		threads := ctx.GlobalInt(utils.MinerThreadsFlag.Name)
   458  		//cpu miner
   459  		cpuMinerAgent := miner.NewCpuAgent(ethereum.BlockChain(), ethereum.Engine())
   460  		ethereum.Miner().Register(cpuMinerAgent)
   461  		if err := ethereum.StartMining(threads); err != nil {
   462  			utils.Fatalf("Failed to start mining: %v", err)
   463  		}
   464  	}
   465  }
   466  
   467  // unlockAccounts unlocks any account specifically requested.
   468  func unlockAccounts(ctx *cli.Context, stack *node.Node) {
   469  	var unlocks []string
   470  	inputs := strings.Split(ctx.GlobalString(utils.UnlockedAccountFlag.Name), ",")
   471  	for _, input := range inputs {
   472  		if trimmed := strings.TrimSpace(input); trimmed != "" {
   473  			unlocks = append(unlocks, trimmed)
   474  		}
   475  	}
   476  	// Short circuit if there is no account to unlock.
   477  	if len(unlocks) == 0 {
   478  		return
   479  	}
   480  	// If insecure account unlocking is not allowed if node's APIs are exposed to external.
   481  	// Print warning log to user and skip unlocking.
   482  	if !stack.Config().InsecureUnlockAllowed && stack.Config().ExtRPCEnabled() {
   483  		utils.Fatalf("Account unlock with HTTP access is forbidden!")
   484  	}
   485  	ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
   486  	passwords := utils.MakePasswordList(ctx)
   487  	for i, account := range unlocks {
   488  		unlockAccount(ks, account, i, passwords)
   489  	}
   490  }