github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/cmd/geth/cmd.go (about)

     1  // Copyright 2014 The go-ethereum Authors
     2  // This file is part of go-ethereum.
     3  //
     4  // go-ethereum 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-ethereum 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-ethereum. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package main
    18  
    19  import (
    20  	"bufio"
    21  	"errors"
    22  	"fmt"
    23  	"io"
    24  	"io/ioutil"
    25  	"os"
    26  	"os/signal"
    27  	"path/filepath"
    28  	"runtime"
    29  	"strconv"
    30  	"strings"
    31  	"syscall"
    32  	"time"
    33  
    34  	"github.com/ethereumproject/ethash"
    35  	"github.com/ethereumproject/go-ethereum/common"
    36  	"github.com/ethereumproject/go-ethereum/core"
    37  	"github.com/ethereumproject/go-ethereum/core/state"
    38  	"github.com/ethereumproject/go-ethereum/core/types"
    39  	"github.com/ethereumproject/go-ethereum/eth"
    40  	"github.com/ethereumproject/go-ethereum/event"
    41  	"github.com/ethereumproject/go-ethereum/logger"
    42  	"github.com/ethereumproject/go-ethereum/logger/glog"
    43  	"github.com/ethereumproject/go-ethereum/node"
    44  	"github.com/ethereumproject/go-ethereum/pow"
    45  	"github.com/ethereumproject/go-ethereum/rlp"
    46  	"gopkg.in/urfave/cli.v1"
    47  	"math"
    48  )
    49  
    50  const (
    51  	importBatchSize = 2500
    52  )
    53  
    54  // Fatalf formats a message to standard error and exits the program.
    55  // The message is also printed to standard output if standard error
    56  // is redirected to a different file.
    57  func Fatalf(format string, args ...interface{}) {
    58  	w := io.MultiWriter(os.Stdout, os.Stderr)
    59  	if runtime.GOOS == "windows" {
    60  		// The SameFile check below doesn't work on Windows.
    61  		// stdout is unlikely to get redirected though, so just print there.
    62  		w = os.Stdout
    63  	} else {
    64  		outf, _ := os.Stdout.Stat()
    65  		errf, _ := os.Stderr.Stat()
    66  		if outf != nil && errf != nil && os.SameFile(outf, errf) {
    67  			w = os.Stderr
    68  		}
    69  	}
    70  	fmt.Fprintf(w, "Fatal: "+format+"\n", args...)
    71  	logger.Flush()
    72  	os.Exit(1)
    73  }
    74  
    75  func StartNode(stack *node.Node) {
    76  	var startTime time.Time
    77  	if err := stack.Start(); err != nil {
    78  		Fatalf("Error starting protocol stack: %v", err)
    79  	} else {
    80  		startTime = time.Now()
    81  	}
    82  
    83  	// mlog
    84  	nodeInfo := stack.Server().NodeInfo()
    85  	cconf := core.GetCacheChainConfig()
    86  	if cconf == nil {
    87  		Fatalf("Nil chain configuration")
    88  	}
    89  
    90  	if cid := common.GetClientSessionIdentity(); cid != nil {
    91  		cid.Version = Version
    92  	}
    93  
    94  	getcmpts := func() string {
    95  		var ss []string
    96  		for c := range logger.GetMLogRegistryActive() {
    97  			ss = append(ss, string(c))
    98  		}
    99  		return strings.Join(ss, ",")
   100  	}
   101  
   102  	// Assign shared start/stop details
   103  	details := []interface{}{
   104  		nodeInfo.ID,
   105  		nodeInfo.Name,
   106  		nodeInfo.Enode,
   107  		nodeInfo.IP,
   108  		stack.Server().MaxPeers,
   109  		cconf.Name,
   110  		cconf.Identity,
   111  		cconf.Network,
   112  		getcmpts(),
   113  		common.GetClientSessionIdentity(),
   114  	}
   115  
   116  	mlogClientStartup.AssignDetails(
   117  		details...,
   118  	).Send(mlogClient)
   119  
   120  	go func() {
   121  		// sigc is a single-val channel for listening to program interrupt
   122  		var sigc = make(chan os.Signal, 1)
   123  		signal.Notify(sigc, os.Interrupt, syscall.SIGTERM)
   124  		defer signal.Stop(sigc)
   125  		sig := <-sigc
   126  		glog.V(logger.Warn).Warnf("Got %v, shutting down...", sig)
   127  		glog.D(logger.Warn).Warnf("Got %v, shutting down...", sig)
   128  		fails := make(chan error, 1)
   129  		var stopError error
   130  		go func(fs chan error) {
   131  			for {
   132  				select {
   133  				case e := <-fs:
   134  					if e != nil {
   135  						stopError = e
   136  						glog.V(logger.Error).Errorf("node stop failure: %v", e)
   137  					}
   138  				}
   139  			}
   140  		}(fails)
   141  
   142  		go func(stack *node.Node) {
   143  			defer func() {
   144  				close(fails)
   145  
   146  				// mlog shutdown
   147  				details = append(details, sig.String())
   148  				details = append(details, stopError)
   149  				details = append(details, int(time.Since(startTime).Seconds()))
   150  				mlogClientShutdown.AssignDetails(
   151  					details...,
   152  				).Send(mlogClient)
   153  
   154  				// Ensure any write-pending I/O gets written.
   155  				glog.Flush()
   156  			}()
   157  			fails <- stack.Stop()
   158  		}(stack)
   159  
   160  		for i := 3; i > 0; i-- {
   161  			<-sigc
   162  			if i > 1 {
   163  				glog.D(logger.Warn).Warnf("Already shutting down, interrupt %d more times for panic.", i-1)
   164  			}
   165  		}
   166  		glog.Fatal("Forced quit.")
   167  	}()
   168  }
   169  
   170  // Chain imports a blockchain.
   171  func ImportChain(chain *core.BlockChain, fn string) error {
   172  	// Watch for Ctrl-C while the import is running.
   173  	// If a signal is received, the import will stop at the next batch.
   174  	interrupt := make(chan os.Signal, 1)
   175  	stop := make(chan struct{})
   176  	signal.Notify(interrupt, os.Interrupt)
   177  	defer signal.Stop(interrupt)
   178  	defer close(interrupt)
   179  	go func() {
   180  		if _, ok := <-interrupt; ok {
   181  			glog.D(logger.Warn).Warnln("caught interrupt during import, will stop at next batch")
   182  		}
   183  		close(stop)
   184  	}()
   185  	checkInterrupt := func() bool {
   186  		select {
   187  		case <-stop:
   188  			return true
   189  		default:
   190  			return false
   191  		}
   192  	}
   193  
   194  	glog.D(logger.Error).Infoln("Importing blockchain ", fn)
   195  	fh, err := os.Open(fn)
   196  	if err != nil {
   197  		return err
   198  	}
   199  	defer fh.Close()
   200  	stream := rlp.NewStream(fh, 0)
   201  
   202  	// Run actual the import.
   203  	blocks := make(types.Blocks, importBatchSize)
   204  	n := 0
   205  	for batch := 0; ; batch++ {
   206  		// Load a batch of RLP blocks.
   207  		if checkInterrupt() {
   208  			return fmt.Errorf("interrupted")
   209  		}
   210  		i := 0
   211  		for ; i < importBatchSize; i++ {
   212  			var b types.Block
   213  			if err := stream.Decode(&b); err == io.EOF {
   214  				break
   215  			} else if err != nil {
   216  				return fmt.Errorf("at block %d: %v", n, err)
   217  			}
   218  			// don't import first block
   219  			if b.NumberU64() == 0 {
   220  				i--
   221  				continue
   222  			}
   223  			blocks[i] = &b
   224  			n++
   225  		}
   226  		if i == 0 {
   227  			break
   228  		}
   229  		// Import the batch.
   230  		if checkInterrupt() {
   231  			return fmt.Errorf("interrupted")
   232  		}
   233  		if hasAllBlocks(chain, blocks[:i]) {
   234  			glog.D(logger.Warn).Warnf("skipping batch %d, all blocks present [%x / %x]",
   235  				batch, blocks[0].Hash().Bytes()[:4], blocks[i-1].Hash().Bytes()[:4])
   236  			continue
   237  		}
   238  
   239  		if res := chain.InsertChain(blocks[:i]); res.Error != nil {
   240  			return fmt.Errorf("invalid block %d: %v", n, res.Error)
   241  		}
   242  	}
   243  	return nil
   244  }
   245  
   246  func hasAllBlocks(chain *core.BlockChain, bs []*types.Block) bool {
   247  	for _, b := range bs {
   248  		if !chain.HasBlock(b.Hash()) {
   249  			return false
   250  		}
   251  	}
   252  	return true
   253  }
   254  
   255  func ExportChain(blockchain *core.BlockChain, fn string) error {
   256  	glog.D(logger.Warn).Infoln("Exporting blockchain to", fn, "(this may take a while)...")
   257  	fh, err := os.OpenFile(fn, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
   258  	if err != nil {
   259  		return err
   260  	}
   261  	defer fh.Close()
   262  	if err := blockchain.Export(fh); err != nil {
   263  		return err
   264  	}
   265  	glog.D(logger.Error).Infoln("Exported blockchain to ", fn)
   266  	return nil
   267  }
   268  
   269  func ExportAppendChain(blockchain *core.BlockChain, fn string, first uint64, last uint64) error {
   270  	glog.D(logger.Warn).Infoln("Exporting blockchain to ", fn)
   271  	// TODO verify mode perms
   272  	fh, err := os.OpenFile(fn, os.O_CREATE|os.O_APPEND|os.O_WRONLY, os.ModePerm)
   273  	if err != nil {
   274  		return err
   275  	}
   276  	defer fh.Close()
   277  	if err := blockchain.ExportN(fh, first, last); err != nil {
   278  		return err
   279  	}
   280  	glog.D(logger.Error).Infoln("Exported blockchain to ", fn)
   281  	return nil
   282  }
   283  
   284  func withLineBreak(s string) string {
   285  	return s + "\n"
   286  }
   287  
   288  func formatStatusKeyValue(prefix string, ss ...interface{}) (s string) {
   289  
   290  	s = ""
   291  	// Single arg; category? ie Forks?
   292  	if len(ss) == 1 {
   293  		s += logger.ColorBlue(fmt.Sprintf("%v", ss[0]))
   294  	}
   295  	if len(ss) == 2 {
   296  		if ss[0] == "" {
   297  			s += fmt.Sprintf("%v", logger.ColorGreen(fmt.Sprintf("%v", ss[1])))
   298  		} else {
   299  			s += fmt.Sprintf("%v: %v", ss[0], logger.ColorGreen(fmt.Sprintf("%v", ss[1])))
   300  		}
   301  	}
   302  	if len(ss) > 2 {
   303  		s += fmt.Sprintf("%v:", ss[0])
   304  		for i := 2; i < len(ss); i++ {
   305  			s += withLineBreak(fmt.Sprintf("    %v", logger.ColorGreen(fmt.Sprintf("%v", ss[i]))))
   306  		}
   307  	}
   308  
   309  	return withLineBreak(prefix + s)
   310  }
   311  
   312  type printable struct {
   313  	indent int
   314  	key    string
   315  	val    interface{}
   316  }
   317  
   318  var indent string = "    "
   319  
   320  // For use by 'status' command.
   321  // These are one of doing it, with each key/val per line and some appropriate indentations to signal grouping/parentage.
   322  // ... But there might be a more elegant way using columns and stuff. VeryPretty?
   323  func formatSufficientChainConfigPretty(config *core.SufficientChainConfig) (s []string) {
   324  	ss := []printable{}
   325  
   326  	// Chain identifiers.
   327  	ss = append(ss, printable{0, "Chain identity", config.Identity})
   328  	ss = append(ss, printable{0, "Chain name", config.Name})
   329  
   330  	// Genesis.
   331  	ss = append(ss, printable{0, "Genesis", nil})
   332  	ss = append(ss, printable{1, "Nonce", config.Genesis.Nonce})
   333  	ss = append(ss, printable{1, "Coinbase", config.Genesis.Coinbase})
   334  	ss = append(ss, printable{1, "Extra data", config.Genesis.ExtraData})
   335  	ss = append(ss, printable{1, "Gas limit", config.Genesis.GasLimit})
   336  	ss = append(ss, printable{1, "Difficulty", config.Genesis.Difficulty})
   337  	ss = append(ss, printable{1, "Time", config.Genesis.Timestamp})
   338  
   339  	lenAlloc := len(config.Genesis.Alloc)
   340  	ss = append(ss, printable{1, "Number of allocations", lenAlloc})
   341  
   342  	// Chain configuration.
   343  	ss = append(ss, printable{0, "Chain Configuration", nil})
   344  	ss = append(ss, printable{1, "Forks", nil})
   345  	for _, v := range config.ChainConfig.Forks {
   346  		ss = append(ss, printable{2, "Name", v.Name})
   347  		ss = append(ss, printable{2, "Block", v.Block})
   348  		if !v.RequiredHash.IsEmpty() {
   349  			ss = append(ss, printable{2, "Required hash", v.RequiredHash.Hex()})
   350  		}
   351  		for _, fv := range v.Features {
   352  			ss = append(ss, printable{3, fv.ID, nil})
   353  			for k, ffv := range fv.Options {
   354  				ss = append(ss, printable{4, k, ffv})
   355  			}
   356  		}
   357  	}
   358  	ss = append(ss, printable{1, "Bad hashes", nil})
   359  	for _, v := range config.ChainConfig.BadHashes {
   360  		ss = append(ss, printable{2, "Block", v.Block})
   361  		ss = append(ss, printable{2, "Hash", v.Hash.Hex()})
   362  	}
   363  
   364  	for _, v := range ss {
   365  		if v.val != nil {
   366  			s = append(s, formatStatusKeyValue(strings.Repeat(indent, v.indent), v.key, v.val))
   367  		} else {
   368  			s = append(s, formatStatusKeyValue(strings.Repeat(indent, v.indent), v.key))
   369  		}
   370  	}
   371  
   372  	return s
   373  }
   374  
   375  func formatEthConfigPretty(ethConfig *eth.Config) (s []string) {
   376  	ss := []printable{}
   377  
   378  	// NetworkID
   379  	ss = append(ss, printable{0, "Network", ethConfig.NetworkId})
   380  	// FastSync?
   381  	ss = append(ss, printable{0, "Fast sync", ethConfig.FastSync})
   382  	// BlockChainVersion
   383  	ss = append(ss, printable{0, "Blockchain version", ethConfig.BlockChainVersion})
   384  	// DatabaseCache
   385  	ss = append(ss, printable{0, "Database cache (MB)", ethConfig.DatabaseCache})
   386  	// DatabaseHandles
   387  	ss = append(ss, printable{0, "Database file handles", ethConfig.DatabaseHandles})
   388  	// NatSpec?
   389  	ss = append(ss, printable{0, "NAT spec", ethConfig.NatSpec})
   390  	// AutoDAG?
   391  	ss = append(ss, printable{0, "Auto DAG", ethConfig.AutoDAG})
   392  	// PowTest?
   393  	ss = append(ss, printable{0, "Pow test", ethConfig.PowTest})
   394  	// PowShared?
   395  	ss = append(ss, printable{0, "Pow shared", ethConfig.PowShared})
   396  	// SolcPath
   397  	ss = append(ss, printable{0, "Solc path", ethConfig.SolcPath})
   398  
   399  	// Account Manager
   400  	lenAccts := len(ethConfig.AccountManager.Accounts())
   401  	ss = append(ss, printable{0, "Account Manager", nil})
   402  	//Number of accounts
   403  	ss = append(ss, printable{1, "Number of accounts", lenAccts})
   404  	// keystore not exported
   405  	// Keystore
   406  	//		Dir
   407  	//		ScryptN
   408  	//		ScryptP
   409  	// Etherbase (if set)
   410  	ss = append(ss, printable{0, "Etherbase", ethConfig.Etherbase.Hex()})
   411  	// GasPrice
   412  	ss = append(ss, printable{0, "Gas price", ethConfig.GasPrice})
   413  	ss = append(ss, printable{0, "GPO min gas price", ethConfig.GpoMinGasPrice})
   414  	ss = append(ss, printable{0, "GPO max gas price", ethConfig.GpoMaxGasPrice})
   415  	// MinerThreads
   416  	ss = append(ss, printable{0, "Miner threads", ethConfig.MinerThreads})
   417  
   418  	for _, v := range ss {
   419  		if v.val != nil {
   420  			s = append(s, formatStatusKeyValue(strings.Repeat(indent, v.indent), v.key, v.val))
   421  		} else {
   422  			s = append(s, formatStatusKeyValue(strings.Repeat(indent, v.indent), v.key))
   423  		}
   424  	}
   425  	return s
   426  }
   427  
   428  func formatStackConfigPretty(stackConfig *node.Config) (s []string) {
   429  
   430  	ss := []printable{}
   431  	// Name
   432  	ss = append(ss, printable{0, "Name", stackConfig.Name})
   433  	// Datadir
   434  	ss = append(ss, printable{0, "Node data dir", stackConfig.DataDir})
   435  	// IPCPath
   436  	ss = append(ss, printable{0, "IPC path", stackConfig.IPCPath})
   437  	// PrivateKey?
   438  	if stackConfig.PrivateKey != nil {
   439  		ss = append(ss, printable{1, "Private key", nil})
   440  		ss = append(ss, printable{2, "Private key", nil})
   441  		ss = append(ss, printable{2, "X", stackConfig.PrivateKey.PublicKey.X})
   442  		ss = append(ss, printable{2, "Y", stackConfig.PrivateKey.PublicKey.Y})
   443  	}
   444  	// Discovery?
   445  	ss = append(ss, printable{0, "Discovery", !stackConfig.NoDiscovery})
   446  	// BoostrapNodes
   447  	ss = append(ss, printable{0, "Bootstrap nodes", nil})
   448  	for _, n := range stackConfig.BootstrapNodes {
   449  		ss = append(ss, printable{1, "", n.String()})
   450  	}
   451  	// ListenAddrg
   452  	sla := stackConfig.ListenAddr
   453  	if sla == ":0" {
   454  		sla += " (OS will pick)"
   455  	}
   456  	ss = append(ss, printable{0, "Listen address", sla})
   457  	// NAT
   458  	ss = append(ss, printable{0, "NAT", stackConfig.NAT.String()})
   459  	// MaxPeers
   460  	ss = append(ss, printable{0, "Max peers", stackConfig.MaxPeers})
   461  	// MaxPendingPeers
   462  	ss = append(ss, printable{0, "Max pending peers", stackConfig.MaxPendingPeers})
   463  	// HTTP
   464  	ss = append(ss, printable{0, "HTTP", nil})
   465  	// HTTPHost
   466  	ss = append(ss, printable{1, "host", stackConfig.HTTPHost})
   467  	// HTTPPort
   468  	ss = append(ss, printable{1, "port", stackConfig.HTTPPort})
   469  	// HTTPCors
   470  	ss = append(ss, printable{1, "CORS", stackConfig.HTTPCors})
   471  	// HTTPModules[]
   472  	ss = append(ss, printable{1, "modules", stackConfig.HTTPModules})
   473  	// Endpoint()
   474  	ss = append(ss, printable{1, "endpoint", stackConfig.HTTPEndpoint()})
   475  	// WS
   476  	ss = append(ss, printable{0, "WS", nil})
   477  	// WSHost
   478  	ss = append(ss, printable{1, "host", stackConfig.WSHost})
   479  	// WSPort
   480  	ss = append(ss, printable{1, "port", stackConfig.WSPort})
   481  	// WSOrigins
   482  	ss = append(ss, printable{1, "origins", stackConfig.WSOrigins})
   483  	// WSModules[]
   484  	ss = append(ss, printable{1, "modules", stackConfig.WSModules})
   485  	// Endpoint()
   486  	ss = append(ss, printable{1, "endpoint", stackConfig.WSEndpoint()})
   487  
   488  	for _, v := range ss {
   489  		if v.val != nil {
   490  			s = append(s, formatStatusKeyValue(strings.Repeat(indent, v.indent), v.key, v.val))
   491  		} else {
   492  			s = append(s, formatStatusKeyValue(strings.Repeat(indent, v.indent), v.key))
   493  		}
   494  	}
   495  	return s
   496  }
   497  
   498  func formatBlockPretty(b *types.Block) (ss []printable) {
   499  	bh := b.Header()
   500  	ss = append(ss, printable{1, "Number", bh.Number})
   501  	ss = append(ss, printable{1, "Hash (hex)", bh.Hash().Hex()})
   502  	ss = append(ss, printable{1, "Parent hash (hex)", bh.ParentHash.Hex()})
   503  	ss = append(ss, printable{1, "Nonce (uint64)", bh.Nonce.Uint64()})
   504  	ss = append(ss, printable{1, "Time", fmt.Sprintf("%v (%v)", bh.Time, time.Unix(int64(bh.Time.Uint64()), 0))})
   505  	ss = append(ss, printable{1, "Difficulty", bh.Difficulty})
   506  	ss = append(ss, printable{1, "Coinbase", bh.Coinbase.Hex()})
   507  	ss = append(ss, printable{1, "Tx hash (hex)", bh.TxHash.Hex()})
   508  	ss = append(ss, printable{1, "Bloom (string)", string(bh.Bloom.Bytes())})
   509  	ss = append(ss, printable{1, "Gas limit", bh.GasLimit})
   510  	ss = append(ss, printable{1, "Gas used", bh.GasUsed})
   511  	ss = append(ss, printable{1, "Extra data (bytes)", bh.Extra})
   512  	return ss
   513  }
   514  
   515  func formatChainDataPretty(datadir string, chain *core.BlockChain) (s []string) {
   516  	ss := []printable{}
   517  
   518  	ss = append(ss, printable{0, "Chain data dir", datadir})
   519  
   520  	ss = append(ss, printable{0, "Genesis", nil})
   521  	ss = append(ss, formatBlockPretty(chain.Genesis())...)
   522  
   523  	currentBlock := chain.CurrentBlock()
   524  	ss = append(ss, printable{0, "Current block", nil})
   525  	ss = append(ss, formatBlockPretty(currentBlock)...)
   526  
   527  	currentFastBlock := chain.CurrentFastBlock()
   528  	ss = append(ss, printable{0, "Current fast block", nil})
   529  	ss = append(ss, formatBlockPretty(currentFastBlock)...)
   530  
   531  	for _, v := range ss {
   532  		if v.val != nil {
   533  			s = append(s, formatStatusKeyValue(strings.Repeat(indent, v.indent), v.key, v.val))
   534  		} else {
   535  			s = append(s, formatStatusKeyValue(strings.Repeat(indent, v.indent), v.key))
   536  		}
   537  	}
   538  	return s
   539  }
   540  
   541  func status(ctx *cli.Context) error {
   542  
   543  	shouldUseExisting := false
   544  	datadir := MustMakeChainDataDir(ctx)
   545  	chaindatadir := filepath.Join(datadir, "chaindata")
   546  	if di, e := os.Stat(chaindatadir); e == nil && di.IsDir() {
   547  		shouldUseExisting = true
   548  	}
   549  	// Makes sufficient configuration from JSON file or DB pending flags.
   550  	// Delegates flag usage.
   551  	config := mustMakeSufficientChainConfig(ctx)
   552  
   553  	// Configure the Ethereum service
   554  	ethConf := mustMakeEthConf(ctx, config)
   555  
   556  	// Configure node's service container.
   557  	name := makeNodeName(Version, ctx)
   558  	stackConf, _ := mustMakeStackConf(ctx, name, config)
   559  
   560  	sep := glog.Separator("-")
   561  	printme := []struct {
   562  		title   string
   563  		keyVals []string
   564  	}{
   565  		{"Chain configuration", formatSufficientChainConfigPretty(config)},
   566  		{"Ethereum configuration", formatEthConfigPretty(ethConf)},
   567  		{"Node configuration", formatStackConfigPretty(stackConf)},
   568  	}
   569  
   570  	s := "\n"
   571  
   572  	for _, p := range printme {
   573  		s += withLineBreak(sep)
   574  		// right align category title
   575  		s += withLineBreak(strings.Repeat(" ", len(sep)-len(p.title)) + logger.ColorBlue(p.title))
   576  		for _, v := range p.keyVals {
   577  			s += v
   578  		}
   579  	}
   580  	glog.D(logger.Warn).Infoln(s)
   581  
   582  	// Return here if database has not been initialized.
   583  	if !shouldUseExisting {
   584  		glog.D(logger.Warn).Warnln("Geth has not been initialized; no database information available yet.")
   585  		return nil
   586  	}
   587  
   588  	chaindata, cdb := MakeChain(ctx)
   589  	defer cdb.Close()
   590  	s = "\n"
   591  	s += withLineBreak(sep)
   592  	title := "Chain database status"
   593  	s += withLineBreak(strings.Repeat(" ", len(sep)-len(title)) + logger.ColorBlue(title))
   594  	for _, v := range formatChainDataPretty(datadir, chaindata) {
   595  		s += v
   596  	}
   597  	glog.D(logger.Warn).Infoln(s)
   598  
   599  	return nil
   600  }
   601  
   602  func rollback(ctx *cli.Context) error {
   603  	index := ctx.Args().First()
   604  	if len(index) == 0 {
   605  		glog.Fatal("missing argument: use `rollback 12345` to specify required block number to roll back to")
   606  		return errors.New("invalid flag usage")
   607  	}
   608  
   609  	blockIndex, err := strconv.ParseUint(index, 10, 64)
   610  	if err != nil {
   611  		glog.Fatalf("invalid argument: use `rollback 12345`, were '12345' is a required number specifying which block number to roll back to")
   612  		return errors.New("invalid flag usage")
   613  	}
   614  
   615  	bc, chainDB := MakeChain(ctx)
   616  	defer chainDB.Close()
   617  
   618  	glog.D(logger.Warn).Infoln("Rolling back blockchain...")
   619  
   620  	if err := bc.SetHead(blockIndex); err != nil {
   621  		glog.D(logger.Error).Errorf("error setting head: %v", err)
   622  	}
   623  
   624  	// Check if *neither* block nor fastblock numbers match desired head number
   625  	nowCurrentHead := bc.CurrentBlock().Number().Uint64()
   626  	nowCurrentFastHead := bc.CurrentFastBlock().Number().Uint64()
   627  	if nowCurrentHead != blockIndex && nowCurrentFastHead != blockIndex {
   628  		glog.Fatalf("ERROR: Wanted rollback to set head to: %v, instead current head is: %v", blockIndex, nowCurrentHead)
   629  	}
   630  	glog.D(logger.Error).Infof("Success. Head block set to: %v", nowCurrentHead)
   631  	return nil
   632  }
   633  
   634  // dumpChainConfig exports chain configuration based on context to JSON file.
   635  // It is not compatible with --chain flag; it is intended to move from default configs -> file,
   636  // and not the other way around.
   637  func dumpChainConfig(ctx *cli.Context) error {
   638  
   639  	chainIdentity := mustMakeChainIdentity(ctx)
   640  	if !(core.ChainIdentitiesMain[chainIdentity] || core.ChainIdentitiesMorden[chainIdentity]) {
   641  		glog.Fatal("Dump config should only be used with default chain configurations (mainnet or morden).")
   642  	}
   643  
   644  	glog.D(logger.Warn).Infof("Dumping configuration for: %v", chainIdentity)
   645  
   646  	chainConfigFilePath := ctx.Args().First()
   647  	chainConfigFilePath = filepath.Clean(chainConfigFilePath)
   648  
   649  	if chainConfigFilePath == "" || chainConfigFilePath == "/" || chainConfigFilePath == "." {
   650  		glog.Fatalf("Given filepath to export chain configuration was blank or invalid; it was: '%v'. It cannot be blank. You typed: %v ", chainConfigFilePath, ctx.Args().First())
   651  		return errors.New("invalid required filepath argument")
   652  	}
   653  
   654  	fb := filepath.Dir(chainConfigFilePath)
   655  	di, de := os.Stat(fb)
   656  	if de != nil {
   657  		if os.IsNotExist(de) {
   658  			glog.V(logger.Warn).Infof("Directory path '%v' does not yet exist. Will create.", fb)
   659  			if e := os.MkdirAll(fb, os.ModePerm); e != nil {
   660  				glog.Fatalf("Could not create necessary directories: %v", e)
   661  			}
   662  			di, _ = os.Stat(fb) // update var with new dir info
   663  		} else {
   664  			glog.V(logger.Error).Errorf("err: %v (at '%v')", de, fb)
   665  		}
   666  	}
   667  	if !di.IsDir() {
   668  		glog.Fatalf("'%v' must be a directory", fb)
   669  	}
   670  
   671  	// Implicitly favor Morden because it is a smaller, simpler configuration,
   672  	// so I expect it to be used more frequently than mainnet.
   673  	genesisDump := core.DefaultConfigMorden.Genesis
   674  	netId := 2
   675  	stateConf := &core.StateConfig{StartingNonce: state.DefaultTestnetStartingNonce}
   676  	if !chainIsMorden(ctx) {
   677  		genesisDump = core.DefaultConfigMainnet.Genesis
   678  		netId = eth.NetworkId
   679  		stateConf = nil
   680  	}
   681  
   682  	chainConfig := MustMakeChainConfigFromDefaults(ctx)
   683  	var nodes []string
   684  	for _, node := range MakeBootstrapNodesFromContext(ctx) {
   685  		nodes = append(nodes, node.String())
   686  	}
   687  
   688  	var currentConfig = &core.SufficientChainConfig{
   689  		Identity:    chainIdentity,
   690  		Name:        mustMakeChainConfigNameDefaulty(ctx),
   691  		Network:     netId,
   692  		State:       stateConf,
   693  		Consensus:   "ethash",
   694  		Genesis:     genesisDump,
   695  		ChainConfig: chainConfig.SortForks(), // get current/contextualized chain config
   696  		Bootstrap:   nodes,
   697  	}
   698  
   699  	if writeError := currentConfig.WriteToJSONFile(chainConfigFilePath); writeError != nil {
   700  		glog.Fatalf("An error occurred while writing chain configuration: %v", writeError)
   701  		return writeError
   702  	}
   703  
   704  	glog.D(logger.Error).Infoln(fmt.Sprintf("Wrote chain config file to \x1b[32m%s\x1b[39m.", chainConfigFilePath))
   705  	return nil
   706  }
   707  
   708  // startNode boots up the system node and all registered protocols, after which
   709  // it unlocks any requested accounts, and starts the RPC/IPC interfaces and the
   710  // miner.
   711  func startNode(ctx *cli.Context, stack *node.Node) *eth.Ethereum {
   712  	// Start up the node itself
   713  	StartNode(stack)
   714  
   715  	// Unlock any account specifically requested
   716  	var ethereum *eth.Ethereum
   717  	if err := stack.Service(&ethereum); err != nil {
   718  		glog.Fatal("ethereum service not running: ", err)
   719  	}
   720  
   721  	// Start auxiliary services if enabled
   722  	if ctx.GlobalBool(aliasableName(AddrTxIndexFlag.Name, ctx)) && ctx.GlobalBool(aliasableName(AddrTxIndexAutoBuildFlag.Name, ctx)) {
   723  		a := ethereum.BlockChain().GetAtxi()
   724  		if a == nil {
   725  			panic("somehow atxi did not get enabled in backend setup. this is not expected")
   726  		}
   727  		a.AutoMode = true
   728  		go core.BuildAddrTxIndex(ethereum.BlockChain(), ethereum.ChainDb(), a.Db, math.MaxUint64, math.MaxUint64, 10000)
   729  	}
   730  	if ctx.GlobalBool(aliasableName(MiningEnabledFlag.Name, ctx)) {
   731  		if err := ethereum.StartMining(ctx.GlobalInt(aliasableName(MinerThreadsFlag.Name, ctx)), ctx.GlobalString(aliasableName(MiningGPUFlag.Name, ctx))); err != nil {
   732  			glog.Fatalf("Failed to start mining: %v", err)
   733  		}
   734  	}
   735  
   736  	return ethereum
   737  }
   738  
   739  func makedag(ctx *cli.Context) error {
   740  	args := ctx.Args()
   741  	wrongArgs := func() {
   742  		glog.Fatal(`Usage: geth makedag <block number> <outputdir>`)
   743  	}
   744  	switch {
   745  	case len(args) == 2:
   746  		blockNum, err := strconv.ParseUint(args[0], 0, 64)
   747  		dir := args[1]
   748  		if err != nil {
   749  			wrongArgs()
   750  		} else {
   751  			dir = filepath.Clean(dir)
   752  			// seems to require a trailing slash
   753  			if !strings.HasSuffix(dir, "/") {
   754  				dir = dir + "/"
   755  			}
   756  			_, err = ioutil.ReadDir(dir)
   757  			if err != nil {
   758  				glog.Fatal("Can't find dir")
   759  			}
   760  			glog.V(logger.Info).Infoln("making DAG, this could take awhile...")
   761  			glog.D(logger.Warn).Infoln("making DAG, this could take awhile...")
   762  			ethash.MakeDAG(blockNum, dir)
   763  		}
   764  	default:
   765  		wrongArgs()
   766  	}
   767  	return nil
   768  }
   769  
   770  func gpuinfo(ctx *cli.Context) error {
   771  	eth.PrintOpenCLDevices()
   772  	return nil
   773  }
   774  
   775  func gpubench(ctx *cli.Context) error {
   776  	args := ctx.Args()
   777  	wrongArgs := func() {
   778  		glog.Fatal(`Usage: geth gpubench <gpu number>`)
   779  	}
   780  	switch {
   781  	case len(args) == 1:
   782  		n, err := strconv.ParseUint(args[0], 0, 64)
   783  		if err != nil {
   784  			wrongArgs()
   785  		}
   786  		eth.GPUBench(n)
   787  	case len(args) == 0:
   788  		eth.GPUBench(0)
   789  	default:
   790  		wrongArgs()
   791  	}
   792  	return nil
   793  }
   794  
   795  func version(ctx *cli.Context) error {
   796  	fmt.Println("Geth")
   797  	fmt.Println("Version:", Version)
   798  	fmt.Println("Protocol Versions:", eth.ProtocolVersions)
   799  	fmt.Println("Network Id:", ctx.GlobalInt(aliasableName(NetworkIdFlag.Name, ctx)))
   800  	fmt.Println("Go Version:", common.GetClientSessionIdentity().Goversion)
   801  	fmt.Println("Go OS:", common.GetClientSessionIdentity().Goos)
   802  	fmt.Println("Go Arch:", common.GetClientSessionIdentity().Goarch)
   803  	fmt.Println("Machine ID:", common.GetClientSessionIdentity().MachineID)
   804  	fmt.Printf("GOPATH=%s\n", os.Getenv("GOPATH"))
   805  	fmt.Printf("GOROOT=%s\n", runtime.GOROOT())
   806  
   807  	return nil
   808  }
   809  
   810  func stringInSlice(s string, sl []string) bool {
   811  	for _, l := range sl {
   812  		if l == s {
   813  			return true
   814  		}
   815  	}
   816  	return false
   817  }
   818  
   819  // makeMLogDocumentation creates markdown documentation text for, eg. wiki
   820  // That's why it uses 'fmt' instead of glog or log; output with prefixes (glog and log)
   821  // will break markdown.
   822  func makeMLogDocumentation(ctx *cli.Context) error {
   823  	wantComponents := ctx.Args()
   824  
   825  	mlogRegistry := logger.GetMLogRegistryAvailable()
   826  
   827  	// If no components specified, print all.
   828  	if len(wantComponents) == 0 {
   829  		for k := range mlogRegistry {
   830  			wantComponents = append(wantComponents, string(k))
   831  		}
   832  	}
   833  
   834  	// Should throw an error if any unavailable components were specified.
   835  	cs := []string{}
   836  	for c := range mlogRegistry {
   837  		cs = append(cs, string(c))
   838  	}
   839  	for _, c := range wantComponents {
   840  		if !stringInSlice(c, cs) {
   841  			glog.Fatalf("Specified component does not exist: %s\n ? Available components: %v", c, cs)
   842  		}
   843  	}
   844  
   845  	// "table of contents"
   846  	for cmp, lines := range mlogRegistry {
   847  		if !stringInSlice(string(cmp), wantComponents) {
   848  			continue
   849  		}
   850  		fmt.Printf("\n[%s]\n\n", cmp)
   851  		for _, line := range lines {
   852  			// print anchor links ul list items
   853  			if ctx.Bool("md") {
   854  				fmt.Printf("- [%s](#%s)\n", line.EventName(), strings.Replace(line.EventName(), ".", "-", -1))
   855  			} else {
   856  				fmt.Printf("- %s\n", line.EventName())
   857  			}
   858  		}
   859  	}
   860  
   861  	// Only print per-line markdown documentation if -md flag given.
   862  	if ctx.Bool("md") {
   863  		fmt.Println("\n----") // hr
   864  
   865  		// each LINE
   866  		for cmp, lines := range mlogRegistry {
   867  			if !stringInSlice(string(cmp), wantComponents) {
   868  				continue
   869  			}
   870  			for _, line := range lines {
   871  				fmt.Println(line.FormatDocumentation(cmp))
   872  				fmt.Println("----")
   873  			}
   874  		}
   875  	}
   876  
   877  	fmt.Println()
   878  	return nil
   879  }
   880  
   881  func recoverChaindata(ctx *cli.Context) error {
   882  
   883  	// Congruent to MakeChain(), but uses special NewBlockChainDryrun. Avoids a one-off function in flags.go.
   884  	var err error
   885  	sconf := mustMakeSufficientChainConfig(ctx)
   886  	bcdb := MakeChainDatabase(ctx)
   887  	defer bcdb.Close()
   888  
   889  	pow := pow.PoW(core.FakePow{})
   890  	if !ctx.GlobalBool(aliasableName(FakePoWFlag.Name, ctx)) {
   891  		pow = ethash.New()
   892  	} else {
   893  		glog.V(logger.Warn).Info("Consensus: fake")
   894  	}
   895  
   896  	bc, err := core.NewBlockChainDryrun(bcdb, sconf.ChainConfig, pow, new(event.TypeMux))
   897  	if err != nil {
   898  		glog.Fatal("Could not start chain manager: ", err)
   899  	}
   900  
   901  	if blockchainLoadError := bc.LoadLastState(true); blockchainLoadError != nil {
   902  		glog.V(logger.Error).Errorf("Error while loading blockchain: %v", blockchainLoadError)
   903  		// but do not return
   904  	}
   905  
   906  	header := bc.CurrentHeader()
   907  	currentBlock := bc.CurrentBlock()
   908  	currentFastBlock := bc.CurrentFastBlock()
   909  
   910  	glog.D(logger.Error).Infoln("Current status (before recovery attempt):")
   911  	if header != nil {
   912  		glog.D(logger.Error).Infof("Last header: #%d\n", header.Number.Uint64())
   913  		if currentBlock != nil {
   914  			glog.D(logger.Error).Infof("Last block: #%d\n", currentBlock.Number())
   915  		} else {
   916  			glog.D(logger.Error).Errorf("! Last block: nil")
   917  		}
   918  		if currentFastBlock != nil {
   919  			glog.D(logger.Error).Infof("Last fast block: #%d\n", currentFastBlock.Number())
   920  		} else {
   921  			glog.D(logger.Error).Errorln("! Last fast block: nil")
   922  		}
   923  	} else {
   924  		glog.D(logger.Error).Errorln("! Last header: nil")
   925  	}
   926  
   927  	glog.D(logger.Error).Infoln(glog.Separator("-"))
   928  
   929  	glog.D(logger.Error).Infoln("Checking db validity and recoverable data...")
   930  	checkpoint := bc.Recovery(1, 2048)
   931  	glog.D(logger.Error).Infof("Found last recoverable checkpoint=#%d\n", checkpoint)
   932  
   933  	glog.D(logger.Error).Infoln(glog.Separator("-"))
   934  
   935  	glog.D(logger.Error).Infoln("Setting blockchain db head to last safe checkpoint...")
   936  	if setHeadErr := bc.SetHead(checkpoint); setHeadErr != nil {
   937  		glog.D(logger.Error).Errorf("Error setting head: %v\n", setHeadErr)
   938  		return setHeadErr
   939  	}
   940  	return nil
   941  }
   942  
   943  // https://gist.github.com/r0l1/3dcbb0c8f6cfe9c66ab8008f55f8f28b
   944  // askForConfirmation asks the user for confirmation. A user must type in "yes" or "no" and
   945  // then press enter. It has fuzzy matching, so "y", "Y", "yes", "YES", and "Yes" all count as
   946  // confirmations. If the input is not recognized, it will ask again. The function does not return
   947  // until it gets a valid response from the user.
   948  //
   949  // Use 'error' verbosity for logging since this is user-critical and required feedback.
   950  func askForConfirmation(s string) bool {
   951  	reader := bufio.NewReader(os.Stdin)
   952  
   953  	for {
   954  		glog.D(logger.Error).Warnf("%s [y/n]: ", s)
   955  
   956  		response, err := reader.ReadString('\n')
   957  		if err != nil {
   958  			glog.Fatalln(err)
   959  		}
   960  
   961  		response = strings.ToLower(strings.TrimSpace(response))
   962  
   963  		if response == "y" || response == "yes" {
   964  			return true
   965  		} else if response == "n" || response == "no" {
   966  			return false
   967  		} else {
   968  			glog.D(logger.Error).Warnln(glog.Separator("*"))
   969  			glog.D(logger.Error).Errorln("* INVALID RESPONSE: Please respond with [y|yes] or [n|no], or use CTRL-C to abort.")
   970  			glog.D(logger.Error).Warnln(glog.Separator("*"))
   971  		}
   972  	}
   973  }
   974  
   975  // resetChaindata removes (rm -rf's) the /chaindata directory, ensuring
   976  // eradication of any corrupted chain data.
   977  func resetChaindata(ctx *cli.Context) error {
   978  	dir := MustMakeChainDataDir(ctx)
   979  	dir = filepath.Join(dir, "chaindata")
   980  	prompt := fmt.Sprintf("\n\nThis will remove the directory='%s' and all of it's contents.\n** Are you sure you want to remove ALL chain data?", dir)
   981  	c := askForConfirmation(prompt)
   982  	if c {
   983  		if err := os.RemoveAll(dir); err != nil {
   984  			return err
   985  		}
   986  		glog.D(logger.Error).Infof("Successfully removed chaindata directory: '%s'\n", dir)
   987  	} else {
   988  		glog.D(logger.Error).Infoln("Leaving chaindata untouched. As you were.")
   989  	}
   990  	return nil
   991  }