github.com/jeffallen/go-ethereum@v1.1.4-0.20150910155051-571d3236c49c/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  	"fmt"
    21  	"os"
    22  	"path/filepath"
    23  	"strconv"
    24  	"time"
    25  
    26  	"github.com/codegangsta/cli"
    27  	"github.com/ethereum/go-ethereum/cmd/utils"
    28  	"github.com/ethereum/go-ethereum/common"
    29  	"github.com/ethereum/go-ethereum/core"
    30  	"github.com/ethereum/go-ethereum/core/state"
    31  	"github.com/ethereum/go-ethereum/core/types"
    32  	"github.com/ethereum/go-ethereum/logger/glog"
    33  )
    34  
    35  var (
    36  	importCommand = cli.Command{
    37  		Action: importChain,
    38  		Name:   "import",
    39  		Usage:  `import a blockchain file`,
    40  	}
    41  	exportCommand = cli.Command{
    42  		Action: exportChain,
    43  		Name:   "export",
    44  		Usage:  `export blockchain into file`,
    45  		Description: `
    46  Requires a first argument of the file to write to.
    47  Optional second and third arguments control the first and
    48  last block to write. In this mode, the file will be appended
    49  if already existing.
    50  		`,
    51  	}
    52  	upgradedbCommand = cli.Command{
    53  		Action: upgradeDB,
    54  		Name:   "upgradedb",
    55  		Usage:  "upgrade chainblock database",
    56  	}
    57  	removedbCommand = cli.Command{
    58  		Action: removeDB,
    59  		Name:   "removedb",
    60  		Usage:  "Remove blockchain and state databases",
    61  	}
    62  	dumpCommand = cli.Command{
    63  		Action: dump,
    64  		Name:   "dump",
    65  		Usage:  `dump a specific block from storage`,
    66  		Description: `
    67  The arguments are interpreted as block numbers or hashes.
    68  Use "ethereum dump 0" to dump the genesis block.
    69  `,
    70  	}
    71  )
    72  
    73  func importChain(ctx *cli.Context) {
    74  	if len(ctx.Args()) != 1 {
    75  		utils.Fatalf("This command requires an argument.")
    76  	}
    77  	chain, chainDb := utils.MakeChain(ctx)
    78  	start := time.Now()
    79  	err := utils.ImportChain(chain, ctx.Args().First())
    80  	chainDb.Close()
    81  	if err != nil {
    82  		utils.Fatalf("Import error: %v", err)
    83  	}
    84  	fmt.Printf("Import done in %v", time.Since(start))
    85  }
    86  
    87  func exportChain(ctx *cli.Context) {
    88  	if len(ctx.Args()) < 1 {
    89  		utils.Fatalf("This command requires an argument.")
    90  	}
    91  	chain, _ := utils.MakeChain(ctx)
    92  	start := time.Now()
    93  
    94  	var err error
    95  	fp := ctx.Args().First()
    96  	if len(ctx.Args()) < 3 {
    97  		err = utils.ExportChain(chain, fp)
    98  	} else {
    99  		// This can be improved to allow for numbers larger than 9223372036854775807
   100  		first, ferr := strconv.ParseInt(ctx.Args().Get(1), 10, 64)
   101  		last, lerr := strconv.ParseInt(ctx.Args().Get(2), 10, 64)
   102  		if ferr != nil || lerr != nil {
   103  			utils.Fatalf("Export error in parsing parameters: block number not an integer\n")
   104  		}
   105  		if first < 0 || last < 0 {
   106  			utils.Fatalf("Export error: block number must be greater than 0\n")
   107  		}
   108  		err = utils.ExportAppendChain(chain, fp, uint64(first), uint64(last))
   109  	}
   110  
   111  	if err != nil {
   112  		utils.Fatalf("Export error: %v\n", err)
   113  	}
   114  	fmt.Printf("Export done in %v", time.Since(start))
   115  }
   116  
   117  func removeDB(ctx *cli.Context) {
   118  	confirm, err := utils.PromptConfirm("Remove local database?")
   119  	if err != nil {
   120  		utils.Fatalf("%v", err)
   121  	}
   122  
   123  	if confirm {
   124  		fmt.Println("Removing chaindata...")
   125  		start := time.Now()
   126  
   127  		os.RemoveAll(filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), "chaindata"))
   128  
   129  		fmt.Printf("Removed in %v\n", time.Since(start))
   130  	} else {
   131  		fmt.Println("Operation aborted")
   132  	}
   133  }
   134  
   135  func upgradeDB(ctx *cli.Context) {
   136  	glog.Infoln("Upgrading blockchain database")
   137  
   138  	chain, chainDb := utils.MakeChain(ctx)
   139  	v, _ := chainDb.Get([]byte("BlockchainVersion"))
   140  	bcVersion := int(common.NewValue(v).Uint())
   141  	if bcVersion == 0 {
   142  		bcVersion = core.BlockChainVersion
   143  	}
   144  
   145  	// Export the current chain.
   146  	filename := fmt.Sprintf("blockchain_%d_%s.chain", bcVersion, time.Now().Format("20060102_150405"))
   147  	exportFile := filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), filename)
   148  	if err := utils.ExportChain(chain, exportFile); err != nil {
   149  		utils.Fatalf("Unable to export chain for reimport %s", err)
   150  	}
   151  	chainDb.Close()
   152  	os.RemoveAll(filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), "chaindata"))
   153  
   154  	// Import the chain file.
   155  	chain, chainDb = utils.MakeChain(ctx)
   156  	chainDb.Put([]byte("BlockchainVersion"), common.NewValue(core.BlockChainVersion).Bytes())
   157  	err := utils.ImportChain(chain, exportFile)
   158  	chainDb.Close()
   159  	if err != nil {
   160  		utils.Fatalf("Import error %v (a backup is made in %s, use the import command to import it)", err, exportFile)
   161  	} else {
   162  		os.Remove(exportFile)
   163  		glog.Infoln("Import finished")
   164  	}
   165  }
   166  
   167  func dump(ctx *cli.Context) {
   168  	chain, chainDb := utils.MakeChain(ctx)
   169  	for _, arg := range ctx.Args() {
   170  		var block *types.Block
   171  		if hashish(arg) {
   172  			block = chain.GetBlock(common.HexToHash(arg))
   173  		} else {
   174  			num, _ := strconv.Atoi(arg)
   175  			block = chain.GetBlockByNumber(uint64(num))
   176  		}
   177  		if block == nil {
   178  			fmt.Println("{}")
   179  			utils.Fatalf("block not found")
   180  		} else {
   181  			state := state.New(block.Root(), chainDb)
   182  			fmt.Printf("%s\n", state.Dump())
   183  		}
   184  	}
   185  	chainDb.Close()
   186  }
   187  
   188  // hashish returns true for strings that look like hashes.
   189  func hashish(x string) bool {
   190  	_, err := strconv.Atoi(x)
   191  	return err != nil
   192  }
   193  
   194  func closeAll(dbs ...common.Database) {
   195  	for _, db := range dbs {
   196  		db.Close()
   197  	}
   198  }