github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/cmd/geth/chaincmd.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 12:09:28</date>
    10  //</624342590950477824>
    11  
    12  
    13  package main
    14  
    15  import (
    16  	"encoding/json"
    17  	"fmt"
    18  	"os"
    19  	"runtime"
    20  	"strconv"
    21  	"sync/atomic"
    22  	"time"
    23  
    24  	"github.com/ethereum/go-ethereum/cmd/utils"
    25  	"github.com/ethereum/go-ethereum/common"
    26  	"github.com/ethereum/go-ethereum/console"
    27  	"github.com/ethereum/go-ethereum/core"
    28  	"github.com/ethereum/go-ethereum/core/state"
    29  	"github.com/ethereum/go-ethereum/core/types"
    30  	"github.com/ethereum/go-ethereum/eth/downloader"
    31  	"github.com/ethereum/go-ethereum/ethdb"
    32  	"github.com/ethereum/go-ethereum/event"
    33  	"github.com/ethereum/go-ethereum/log"
    34  	"github.com/ethereum/go-ethereum/trie"
    35  	"github.com/syndtr/goleveldb/leveldb/util"
    36  	"gopkg.in/urfave/cli.v1"
    37  )
    38  
    39  var (
    40  	initCommand = cli.Command{
    41  		Action:    utils.MigrateFlags(initGenesis),
    42  		Name:      "init",
    43  		Usage:     "Bootstrap and initialize a new genesis block",
    44  		ArgsUsage: "<genesisPath>",
    45  		Flags: []cli.Flag{
    46  			utils.DataDirFlag,
    47  		},
    48  		Category: "BLOCKCHAIN COMMANDS",
    49  		Description: `
    50  The init command initializes a new genesis block and definition for the network.
    51  This is a destructive action and changes the network in which you will be
    52  participating.
    53  
    54  It expects the genesis file as argument.`,
    55  	}
    56  	importCommand = cli.Command{
    57  		Action:    utils.MigrateFlags(importChain),
    58  		Name:      "import",
    59  		Usage:     "Import a blockchain file",
    60  		ArgsUsage: "<filename> (<filename 2> ... <filename N>) ",
    61  		Flags: []cli.Flag{
    62  			utils.DataDirFlag,
    63  			utils.CacheFlag,
    64  			utils.SyncModeFlag,
    65  			utils.GCModeFlag,
    66  			utils.CacheDatabaseFlag,
    67  			utils.CacheGCFlag,
    68  		},
    69  		Category: "BLOCKCHAIN COMMANDS",
    70  		Description: `
    71  The import command imports blocks from an RLP-encoded form. The form can be one file
    72  with several RLP-encoded blocks, or several files can be used.
    73  
    74  If only one file is used, import error will result in failure. If several files are used,
    75  processing will proceed even if an individual RLP-file import failure occurs.`,
    76  	}
    77  	exportCommand = cli.Command{
    78  		Action:    utils.MigrateFlags(exportChain),
    79  		Name:      "export",
    80  		Usage:     "Export blockchain into file",
    81  		ArgsUsage: "<filename> [<blockNumFirst> <blockNumLast>]",
    82  		Flags: []cli.Flag{
    83  			utils.DataDirFlag,
    84  			utils.CacheFlag,
    85  			utils.SyncModeFlag,
    86  		},
    87  		Category: "BLOCKCHAIN COMMANDS",
    88  		Description: `
    89  Requires a first argument of the file to write to.
    90  Optional second and third arguments control the first and
    91  last block to write. In this mode, the file will be appended
    92  if already existing. If the file ends with .gz, the output will
    93  be gzipped.`,
    94  	}
    95  	importPreimagesCommand = cli.Command{
    96  		Action:    utils.MigrateFlags(importPreimages),
    97  		Name:      "import-preimages",
    98  		Usage:     "Import the preimage database from an RLP stream",
    99  		ArgsUsage: "<datafile>",
   100  		Flags: []cli.Flag{
   101  			utils.DataDirFlag,
   102  			utils.CacheFlag,
   103  			utils.SyncModeFlag,
   104  		},
   105  		Category: "BLOCKCHAIN COMMANDS",
   106  		Description: `
   107  	The import-preimages command imports hash preimages from an RLP encoded stream.`,
   108  	}
   109  	exportPreimagesCommand = cli.Command{
   110  		Action:    utils.MigrateFlags(exportPreimages),
   111  		Name:      "export-preimages",
   112  		Usage:     "Export the preimage database into an RLP stream",
   113  		ArgsUsage: "<dumpfile>",
   114  		Flags: []cli.Flag{
   115  			utils.DataDirFlag,
   116  			utils.CacheFlag,
   117  			utils.SyncModeFlag,
   118  		},
   119  		Category: "BLOCKCHAIN COMMANDS",
   120  		Description: `
   121  The export-preimages command export hash preimages to an RLP encoded stream`,
   122  	}
   123  	copydbCommand = cli.Command{
   124  		Action:    utils.MigrateFlags(copyDb),
   125  		Name:      "copydb",
   126  		Usage:     "Create a local chain from a target chaindata folder",
   127  		ArgsUsage: "<sourceChaindataDir>",
   128  		Flags: []cli.Flag{
   129  			utils.DataDirFlag,
   130  			utils.CacheFlag,
   131  			utils.SyncModeFlag,
   132  			utils.FakePoWFlag,
   133  			utils.TestnetFlag,
   134  			utils.RinkebyFlag,
   135  		},
   136  		Category: "BLOCKCHAIN COMMANDS",
   137  		Description: `
   138  The first argument must be the directory containing the blockchain to download from`,
   139  	}
   140  	removedbCommand = cli.Command{
   141  		Action:    utils.MigrateFlags(removeDB),
   142  		Name:      "removedb",
   143  		Usage:     "Remove blockchain and state databases",
   144  		ArgsUsage: " ",
   145  		Flags: []cli.Flag{
   146  			utils.DataDirFlag,
   147  		},
   148  		Category: "BLOCKCHAIN COMMANDS",
   149  		Description: `
   150  Remove blockchain and state databases`,
   151  	}
   152  	dumpCommand = cli.Command{
   153  		Action:    utils.MigrateFlags(dump),
   154  		Name:      "dump",
   155  		Usage:     "Dump a specific block from storage",
   156  		ArgsUsage: "[<blockHash> | <blockNum>]...",
   157  		Flags: []cli.Flag{
   158  			utils.DataDirFlag,
   159  			utils.CacheFlag,
   160  			utils.SyncModeFlag,
   161  		},
   162  		Category: "BLOCKCHAIN COMMANDS",
   163  		Description: `
   164  The arguments are interpreted as block numbers or hashes.
   165  Use "ethereum dump 0" to dump the genesis block.`,
   166  	}
   167  )
   168  
   169  //initGenesis将初始化给定的JSON格式genesis文件,并将其写为
   170  //如果它不能成功的话,它将很难阻止(也就是说,创世记)。
   171  func initGenesis(ctx *cli.Context) error {
   172  //确保我们有一个有效的Genesis JSON
   173  	genesisPath := ctx.Args().First()
   174  	if len(genesisPath) == 0 {
   175  		utils.Fatalf("Must supply path to genesis JSON file")
   176  	}
   177  	file, err := os.Open(genesisPath)
   178  	if err != nil {
   179  		utils.Fatalf("Failed to read genesis file: %v", err)
   180  	}
   181  	defer file.Close()
   182  
   183  	genesis := new(core.Genesis)
   184  	if err := json.NewDecoder(file).Decode(genesis); err != nil {
   185  		utils.Fatalf("invalid genesis file: %v", err)
   186  	}
   187  //打开初始化完整数据库和轻型数据库
   188  	stack := makeFullNode(ctx)
   189  	for _, name := range []string{"chaindata", "lightchaindata"} {
   190  		chaindb, err := stack.OpenDatabase(name, 0, 0)
   191  		if err != nil {
   192  			utils.Fatalf("Failed to open database: %v", err)
   193  		}
   194  		_, hash, err := core.SetupGenesisBlock(chaindb, genesis)
   195  		if err != nil {
   196  			utils.Fatalf("Failed to write genesis block: %v", err)
   197  		}
   198  		log.Info("Successfully wrote genesis state", "database", name, "hash", hash)
   199  	}
   200  	return nil
   201  }
   202  
   203  func importChain(ctx *cli.Context) error {
   204  	if len(ctx.Args()) < 1 {
   205  		utils.Fatalf("This command requires an argument.")
   206  	}
   207  	stack := makeFullNode(ctx)
   208  	chain, chainDb := utils.MakeChain(ctx, stack)
   209  	defer chainDb.Close()
   210  
   211  //开始定期收集内存配置文件
   212  	var peakMemAlloc, peakMemSys uint64
   213  	go func() {
   214  		stats := new(runtime.MemStats)
   215  		for {
   216  			runtime.ReadMemStats(stats)
   217  			if atomic.LoadUint64(&peakMemAlloc) < stats.Alloc {
   218  				atomic.StoreUint64(&peakMemAlloc, stats.Alloc)
   219  			}
   220  			if atomic.LoadUint64(&peakMemSys) < stats.Sys {
   221  				atomic.StoreUint64(&peakMemSys, stats.Sys)
   222  			}
   223  			time.Sleep(5 * time.Second)
   224  		}
   225  	}()
   226  //导入链
   227  	start := time.Now()
   228  
   229  	if len(ctx.Args()) == 1 {
   230  		if err := utils.ImportChain(chain, ctx.Args().First()); err != nil {
   231  			log.Error("Import error", "err", err)
   232  		}
   233  	} else {
   234  		for _, arg := range ctx.Args() {
   235  			if err := utils.ImportChain(chain, arg); err != nil {
   236  				log.Error("Import error", "file", arg, "err", err)
   237  			}
   238  		}
   239  	}
   240  	chain.Stop()
   241  	fmt.Printf("Import done in %v.\n\n", time.Since(start))
   242  
   243  //输出预压缩状态,主要是查看导入垃圾
   244  	db := chainDb.(*ethdb.LDBDatabase)
   245  
   246  	stats, err := db.LDB().GetProperty("leveldb.stats")
   247  	if err != nil {
   248  		utils.Fatalf("Failed to read database stats: %v", err)
   249  	}
   250  	fmt.Println(stats)
   251  
   252  	ioStats, err := db.LDB().GetProperty("leveldb.iostats")
   253  	if err != nil {
   254  		utils.Fatalf("Failed to read database iostats: %v", err)
   255  	}
   256  	fmt.Println(ioStats)
   257  
   258  	fmt.Printf("Trie cache misses:  %d\n", trie.CacheMisses())
   259  	fmt.Printf("Trie cache unloads: %d\n\n", trie.CacheUnloads())
   260  
   261  //打印导入使用的内存统计信息
   262  	mem := new(runtime.MemStats)
   263  	runtime.ReadMemStats(mem)
   264  
   265  	fmt.Printf("Object memory: %.3f MB current, %.3f MB peak\n", float64(mem.Alloc)/1024/1024, float64(atomic.LoadUint64(&peakMemAlloc))/1024/1024)
   266  	fmt.Printf("System memory: %.3f MB current, %.3f MB peak\n", float64(mem.Sys)/1024/1024, float64(atomic.LoadUint64(&peakMemSys))/1024/1024)
   267  	fmt.Printf("Allocations:   %.3f million\n", float64(mem.Mallocs)/1000000)
   268  	fmt.Printf("GC pause:      %v\n\n", time.Duration(mem.PauseTotalNs))
   269  
   270  	if ctx.GlobalIsSet(utils.NoCompactionFlag.Name) {
   271  		return nil
   272  	}
   273  
   274  //压缩整个数据库以更准确地测量磁盘IO并打印统计信息
   275  	start = time.Now()
   276  	fmt.Println("Compacting entire database...")
   277  	if err = db.LDB().CompactRange(util.Range{}); err != nil {
   278  		utils.Fatalf("Compaction failed: %v", err)
   279  	}
   280  	fmt.Printf("Compaction done in %v.\n\n", time.Since(start))
   281  
   282  	stats, err = db.LDB().GetProperty("leveldb.stats")
   283  	if err != nil {
   284  		utils.Fatalf("Failed to read database stats: %v", err)
   285  	}
   286  	fmt.Println(stats)
   287  
   288  	ioStats, err = db.LDB().GetProperty("leveldb.iostats")
   289  	if err != nil {
   290  		utils.Fatalf("Failed to read database iostats: %v", err)
   291  	}
   292  	fmt.Println(ioStats)
   293  
   294  	return nil
   295  }
   296  
   297  func exportChain(ctx *cli.Context) error {
   298  	if len(ctx.Args()) < 1 {
   299  		utils.Fatalf("This command requires an argument.")
   300  	}
   301  	stack := makeFullNode(ctx)
   302  	chain, _ := utils.MakeChain(ctx, stack)
   303  	start := time.Now()
   304  
   305  	var err error
   306  	fp := ctx.Args().First()
   307  	if len(ctx.Args()) < 3 {
   308  		err = utils.ExportChain(chain, fp)
   309  	} else {
   310  //这可以改进为允许大于9223372036854775807的数字
   311  		first, ferr := strconv.ParseInt(ctx.Args().Get(1), 10, 64)
   312  		last, lerr := strconv.ParseInt(ctx.Args().Get(2), 10, 64)
   313  		if ferr != nil || lerr != nil {
   314  			utils.Fatalf("Export error in parsing parameters: block number not an integer\n")
   315  		}
   316  		if first < 0 || last < 0 {
   317  			utils.Fatalf("Export error: block number must be greater than 0\n")
   318  		}
   319  		err = utils.ExportAppendChain(chain, fp, uint64(first), uint64(last))
   320  	}
   321  
   322  	if err != nil {
   323  		utils.Fatalf("Export error: %v\n", err)
   324  	}
   325  	fmt.Printf("Export done in %v\n", time.Since(start))
   326  	return nil
   327  }
   328  
   329  //importpreimages从指定文件导入preimage数据。
   330  func importPreimages(ctx *cli.Context) error {
   331  	if len(ctx.Args()) < 1 {
   332  		utils.Fatalf("This command requires an argument.")
   333  	}
   334  	stack := makeFullNode(ctx)
   335  	diskdb := utils.MakeChainDatabase(ctx, stack).(*ethdb.LDBDatabase)
   336  
   337  	start := time.Now()
   338  	if err := utils.ImportPreimages(diskdb, ctx.Args().First()); err != nil {
   339  		utils.Fatalf("Export error: %v\n", err)
   340  	}
   341  	fmt.Printf("Export done in %v\n", time.Since(start))
   342  	return nil
   343  }
   344  
   345  //exportpreimages以流式方式将preimage数据转储到指定的JSON文件。
   346  func exportPreimages(ctx *cli.Context) error {
   347  	if len(ctx.Args()) < 1 {
   348  		utils.Fatalf("This command requires an argument.")
   349  	}
   350  	stack := makeFullNode(ctx)
   351  	diskdb := utils.MakeChainDatabase(ctx, stack).(*ethdb.LDBDatabase)
   352  
   353  	start := time.Now()
   354  	if err := utils.ExportPreimages(diskdb, ctx.Args().First()); err != nil {
   355  		utils.Fatalf("Export error: %v\n", err)
   356  	}
   357  	fmt.Printf("Export done in %v\n", time.Since(start))
   358  	return nil
   359  }
   360  
   361  func copyDb(ctx *cli.Context) error {
   362  //确保我们有一个要复制的源链目录
   363  	if len(ctx.Args()) != 1 {
   364  		utils.Fatalf("Source chaindata directory path argument missing")
   365  	}
   366  //初始化要同步到的运行节点的新链
   367  	stack := makeFullNode(ctx)
   368  	chain, chainDb := utils.MakeChain(ctx, stack)
   369  
   370  	syncmode := *utils.GlobalTextMarshaler(ctx, utils.SyncModeFlag.Name).(*downloader.SyncMode)
   371  	dl := downloader.New(syncmode, chainDb, new(event.TypeMux), chain, nil, nil)
   372  
   373  //创建源对等点以满足来自
   374  	db, err := ethdb.NewLDBDatabase(ctx.Args().First(), ctx.GlobalInt(utils.CacheFlag.Name), 256)
   375  	if err != nil {
   376  		return err
   377  	}
   378  	hc, err := core.NewHeaderChain(db, chain.Config(), chain.Engine(), func() bool { return false })
   379  	if err != nil {
   380  		return err
   381  	}
   382  	peer := downloader.NewFakePeer("local", db, hc, dl)
   383  	if err = dl.RegisterPeer("local", 63, peer); err != nil {
   384  		return err
   385  	}
   386  //与模拟对等机同步
   387  	start := time.Now()
   388  
   389  	currentHeader := hc.CurrentHeader()
   390  	if err = dl.Synchronise("local", currentHeader.Hash(), hc.GetTd(currentHeader.Hash(), currentHeader.Number.Uint64()), syncmode); err != nil {
   391  		return err
   392  	}
   393  	for dl.Synchronising() {
   394  		time.Sleep(10 * time.Millisecond)
   395  	}
   396  	fmt.Printf("Database copy done in %v\n", time.Since(start))
   397  
   398  //压缩整个数据库以消除任何同步开销
   399  	start = time.Now()
   400  	fmt.Println("Compacting entire database...")
   401  	if err = chainDb.(*ethdb.LDBDatabase).LDB().CompactRange(util.Range{}); err != nil {
   402  		utils.Fatalf("Compaction failed: %v", err)
   403  	}
   404  	fmt.Printf("Compaction done in %v.\n\n", time.Since(start))
   405  
   406  	return nil
   407  }
   408  
   409  func removeDB(ctx *cli.Context) error {
   410  	stack, _ := makeConfigNode(ctx)
   411  
   412  	for _, name := range []string{"chaindata", "lightchaindata"} {
   413  //首先确保数据库存在
   414  		logger := log.New("database", name)
   415  
   416  		dbdir := stack.ResolvePath(name)
   417  		if !common.FileExist(dbdir) {
   418  			logger.Info("Database doesn't exist, skipping", "path", dbdir)
   419  			continue
   420  		}
   421  //确认删除并执行
   422  		fmt.Println(dbdir)
   423  		confirm, err := console.Stdin.PromptConfirm("Remove this database?")
   424  		switch {
   425  		case err != nil:
   426  			utils.Fatalf("%v", err)
   427  		case !confirm:
   428  			logger.Warn("Database deletion aborted")
   429  		default:
   430  			start := time.Now()
   431  			os.RemoveAll(dbdir)
   432  			logger.Info("Database successfully deleted", "elapsed", common.PrettyDuration(time.Since(start)))
   433  		}
   434  	}
   435  	return nil
   436  }
   437  
   438  func dump(ctx *cli.Context) error {
   439  	stack := makeFullNode(ctx)
   440  	chain, chainDb := utils.MakeChain(ctx, stack)
   441  	for _, arg := range ctx.Args() {
   442  		var block *types.Block
   443  		if hashish(arg) {
   444  			block = chain.GetBlockByHash(common.HexToHash(arg))
   445  		} else {
   446  			num, _ := strconv.Atoi(arg)
   447  			block = chain.GetBlockByNumber(uint64(num))
   448  		}
   449  		if block == nil {
   450  			fmt.Println("{}")
   451  			utils.Fatalf("block not found")
   452  		} else {
   453  			state, err := state.New(block.Root(), state.NewDatabase(chainDb))
   454  			if err != nil {
   455  				utils.Fatalf("could not create new state: %v", err)
   456  			}
   457  			fmt.Printf("%s\n", state.Dump())
   458  		}
   459  	}
   460  	chainDb.Close()
   461  	return nil
   462  }
   463  
   464  //对于看起来像哈希的字符串,hashish返回true。
   465  func hashish(x string) bool {
   466  	_, err := strconv.Atoi(x)
   467  	return err != nil
   468  }
   469