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

     1  // Copyright 2015 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  	"fmt"
    22  	"log"
    23  	"os"
    24  	"path/filepath"
    25  	"strconv"
    26  	"strings"
    27  	"time"
    28  
    29  	"github.com/ethereumproject/go-ethereum/common"
    30  	"github.com/ethereumproject/go-ethereum/core"
    31  	"github.com/ethereumproject/go-ethereum/core/state"
    32  	"github.com/ethereumproject/go-ethereum/core/types"
    33  	"github.com/ethereumproject/go-ethereum/logger/glog"
    34  	"gopkg.in/urfave/cli.v1"
    35  )
    36  
    37  var (
    38  	importCommand = cli.Command{
    39  		Action: importChain,
    40  		Name:   "import",
    41  		Usage:  `Import a blockchain file`,
    42  	}
    43  	exportCommand = cli.Command{
    44  		Action: exportChain,
    45  		Name:   "export",
    46  		Usage:  `Export blockchain into file`,
    47  		Description: `
    48  	Requires a first argument of the file to write to.
    49  	Optional second and third arguments control the first and
    50  	last block to write. In this mode, the file will be appended
    51  	if already existing.
    52  		`,
    53  	}
    54  	upgradedbCommand = cli.Command{
    55  		Action:  upgradeDB,
    56  		Name:    "upgrade-db",
    57  		Aliases: []string{"upgradedb"},
    58  		Usage:   "Upgrade chainblock database",
    59  	}
    60  	dumpCommand = cli.Command{
    61  		Action: dump,
    62  		Name:   "dump",
    63  		Usage:  `Dump a specific block from storage`,
    64  		Description: `
    65  	The arguments are interpreted as block numbers or hashes.
    66  	Use "$ geth dump 0" to dump the genesis block.
    67  		`,
    68  	}
    69  	dumpChainConfigCommand = cli.Command{
    70  		Action:  dumpChainConfig,
    71  		Name:    "dump-chain-config",
    72  		Aliases: []string{"dumpchainconfig"},
    73  		Usage:   "Dump current chain configuration to JSON file [REQUIRED argument: filepath.json]",
    74  		Description: `
    75  	The dump external configuration command writes a JSON file containing pertinent configuration data for
    76  	the configuration of a chain database. It includes genesis block data as well as chain fork settings.
    77  		`,
    78  	}
    79  	rollbackCommand = cli.Command{
    80  		Action:  rollback,
    81  		Name:    "rollback",
    82  		Aliases: []string{"roll-back", "set-head", "sethead"},
    83  		Usage:   "Set current head for blockchain, purging antecedent blocks",
    84  		Description: `
    85  	Rollback set the current head block for block chain already in the database.
    86  	This is a destructive action, purging any block more recent than the index specified.
    87  	Syncing will require downloading contemporary block information from the index onwards.
    88  		`,
    89  	}
    90  	statusCommand = cli.Command{
    91  		Action: status,
    92  		Name:   "status",
    93  		Usage:  "Display the status of the current node",
    94  		Description: `
    95  	Show the status of the current configuration.
    96  		`,
    97  	}
    98  	resetCommand = cli.Command{
    99  		Action: resetChaindata,
   100  		Name:   "reset",
   101  		Usage:  "Reset (remove) the chain database",
   102  		Description: `
   103  		Reset does a hard reset of the entire chain database.
   104  		This is a drastic and irreversible command, and should be used with caution.
   105  		The command will require user confirmation before any action is taken.
   106  		`,
   107  	}
   108  	recoverCommand = cli.Command{
   109  		Action: recoverChaindata,
   110  		Name:   "recover",
   111  		Usage:  "Attempt blockchain data recovery in case of data corruption",
   112  		Description: `
   113  		Recover scans and health-checks all available blockchain data in order
   114  		to recover all consistent and healthy block data. It will remove invalid or
   115  		corrupt block data that may have been caused by hard killing, system failure,
   116  		space limitations, or attack.
   117  		`,
   118  	}
   119  )
   120  
   121  func importChain(ctx *cli.Context) error {
   122  	if len(ctx.Args()) != 1 {
   123  		log.Fatal("This command requires an argument.")
   124  	}
   125  	chain, chainDb := MakeChain(ctx)
   126  	start := time.Now()
   127  	err := ImportChain(chain, ctx.Args().First())
   128  	chainDb.Close()
   129  	if err != nil {
   130  		log.Fatal("Import error: ", err)
   131  	}
   132  	fmt.Printf("Import done in %v", time.Since(start))
   133  	return nil
   134  }
   135  
   136  func exportChain(ctx *cli.Context) error {
   137  	if len(ctx.Args()) < 1 {
   138  		log.Fatal("This command requires an argument.")
   139  	}
   140  	chain, _ := MakeChain(ctx)
   141  	start := time.Now()
   142  
   143  	fp := ctx.Args().First()
   144  	if len(ctx.Args()) < 3 {
   145  		if err := ExportChain(chain, fp); err != nil {
   146  			log.Fatal(err)
   147  		}
   148  	} else {
   149  		// This can be improved to allow for numbers larger than 9223372036854775807
   150  		first, err := strconv.ParseUint(ctx.Args().Get(1), 10, 64)
   151  		if err != nil {
   152  			log.Fatal("export paramater: ", err)
   153  		}
   154  		last, err := strconv.ParseUint(ctx.Args().Get(2), 10, 64)
   155  		if err != nil {
   156  			log.Fatal("export paramater: ", err)
   157  		}
   158  		if err = ExportAppendChain(chain, fp, first, last); err != nil {
   159  			log.Fatal(err)
   160  		}
   161  	}
   162  
   163  	fmt.Printf("Export done in %v", time.Since(start))
   164  	return nil
   165  }
   166  
   167  func upgradeDB(ctx *cli.Context) error {
   168  	glog.Infoln("Upgrading blockchain database")
   169  
   170  	chain, chainDb := MakeChain(ctx)
   171  	bcVersion := core.GetBlockChainVersion(chainDb)
   172  	if bcVersion == 0 {
   173  		bcVersion = core.BlockChainVersion
   174  	}
   175  
   176  	// Export the current chain.
   177  	filename := fmt.Sprintf("blockchain_%d_%s.chain", bcVersion, time.Now().Format("20060102_150405"))
   178  	exportFile := filepath.Join(ctx.GlobalString(DataDirFlag.Name), filename)
   179  	if err := ExportChain(chain, exportFile); err != nil {
   180  		log.Fatal("Unable to export chain for reimport ", err)
   181  	}
   182  	chainDb.Close()
   183  	os.RemoveAll(filepath.Join(ctx.GlobalString(DataDirFlag.Name), "chaindata"))
   184  
   185  	// Import the chain file.
   186  	chain, chainDb = MakeChain(ctx)
   187  	core.WriteBlockChainVersion(chainDb, core.BlockChainVersion)
   188  	err := ImportChain(chain, exportFile)
   189  	chainDb.Close()
   190  	if err != nil {
   191  		log.Fatalf("Import error %v (a backup is made in %s, use the import command to import it)", err, exportFile)
   192  	} else {
   193  		os.Remove(exportFile)
   194  		glog.Infoln("Import finished")
   195  	}
   196  	return nil
   197  }
   198  
   199  // Original use allows n hashes|ints as space-separated arguments, dumping entire state for each block n[x].
   200  // $ geth dump [hash|num] [hash|num] ... [hash|num]
   201  // $ geth dump 0x234234234234233 42 43 0xlksdf234r23r234223
   202  //
   203  // Revised use allows n hashes|ints as comma-separated first argument and n addresses as comma-separated second argument,
   204  // dumping only state information for given addresses if they're present.
   205  // revised use: $ geth dump [hash|num],[hash|num],...,[hash|num] [address],[address],...,[address]
   206  //
   207  // Added unsorted/sorted dumping algorithms.
   208  // unsorted dump is used by default.
   209  // revised use: $ geth dump [sorted] [hash|num],[hash|num],...,[hash|num] [address],[address],...,[address]
   210  
   211  func dump(ctx *cli.Context) error {
   212  
   213  	if ctx.NArg() == 0 {
   214  		return fmt.Errorf("%v: use: $ geth dump [blockHash|blockNum],[blockHash|blockNum] [[addressHex|addressPrefixedHex],[addressHex|addressPrefixedHex]]", ErrInvalidFlag)
   215  	}
   216  
   217  	firstArg := 0
   218  	sorted := ctx.Args()[0] == "sorted"
   219  	if sorted {
   220  		firstArg = 1
   221  	}
   222  
   223  	blocks := strings.Split(ctx.Args()[firstArg], ",")
   224  	addresses := []common.Address{}
   225  	argaddress := ""
   226  	if ctx.NArg() > firstArg+1 {
   227  		argaddress = ctx.Args()[firstArg+1]
   228  	}
   229  
   230  	if argaddress != "" {
   231  		argaddresses := strings.Split(argaddress, ",")
   232  		for _, a := range argaddresses {
   233  			addresses = append(addresses, common.HexToAddress(strings.TrimSpace(a)))
   234  		}
   235  	}
   236  
   237  	chain, chainDb := MakeChain(ctx)
   238  	defer chainDb.Close()
   239  
   240  	prefix := ""
   241  	indent := "    "
   242  
   243  	out := bufio.NewWriter(os.Stdout)
   244  
   245  	if len(blocks) > 1 {
   246  		prefix = indent
   247  		out.WriteString("[\n")
   248  	}
   249  
   250  	for n, b := range blocks {
   251  		b = strings.TrimSpace(b)
   252  		var block *types.Block
   253  		if hashish(b) {
   254  			block = chain.GetBlock(common.HexToHash(b))
   255  		} else {
   256  			num, _ := strconv.Atoi(b)
   257  			block = chain.GetBlockByNumber(uint64(num))
   258  		}
   259  		if block == nil {
   260  			out.WriteString("{}\n")
   261  			log.Fatal("block not found")
   262  		} else {
   263  			state, err := state.New(block.Root(), state.NewDatabase(chainDb))
   264  			if err != nil {
   265  				return fmt.Errorf("could not create new state: %v", err)
   266  			}
   267  
   268  			if n != 0 {
   269  				out.WriteString(",\n")
   270  			}
   271  
   272  			if sorted {
   273  				err = state.SortedDump(addresses, prefix, indent, out)
   274  			} else {
   275  				err = state.UnsortedDump(addresses, prefix, indent, out)
   276  			}
   277  
   278  			if err != nil {
   279  				return err
   280  			}
   281  		}
   282  	}
   283  
   284  	if len(blocks) > 1 {
   285  		out.WriteString("\n]")
   286  	}
   287  
   288  	out.WriteString("\n")
   289  	out.Flush()
   290  
   291  	return nil
   292  }
   293  
   294  // hashish returns true for strings that look like hashes.
   295  func hashish(x string) bool {
   296  	_, err := strconv.Atoi(x)
   297  	return err != nil
   298  }