github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/cmd/geth/chaincmd.go (about)

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