github.com/neatio-net/neatio@v1.7.3-0.20231114194659-f4d7a2226baa/chain/neatio/chaincmd.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"runtime"
     7  	"strconv"
     8  	"sync/atomic"
     9  	"time"
    10  
    11  	"github.com/neatio-net/neatio/neatdb"
    12  	neatptc "github.com/neatio-net/neatio/neatptc"
    13  	"github.com/neatio-net/neatio/params"
    14  
    15  	"github.com/neatio-net/neatio/chain/core"
    16  	"github.com/neatio-net/neatio/chain/core/rawdb"
    17  	"github.com/neatio-net/neatio/chain/core/state"
    18  	"github.com/neatio-net/neatio/chain/core/types"
    19  	"github.com/neatio-net/neatio/chain/log"
    20  	"github.com/neatio-net/neatio/neatptc/downloader"
    21  	"github.com/neatio-net/neatio/utilities/common"
    22  	"github.com/neatio-net/neatio/utilities/console"
    23  	"github.com/neatio-net/neatio/utilities/event"
    24  	"github.com/neatio-net/neatio/utilities/rlp"
    25  	"github.com/neatio-net/neatio/utilities/utils"
    26  	"gopkg.in/urfave/cli.v1"
    27  )
    28  
    29  var (
    30  	initNEATGenesisCmd = cli.Command{
    31  		Action:    utils.MigrateFlags(initNeatGenesis),
    32  		Name:      "init-neatio",
    33  		Usage:     "Initialize Neatio genesis.json file. init-neatio {\"1000000000000000000000000000\",\"100000000000000000000000\"}",
    34  		ArgsUsage: "<genesisPath>",
    35  		Flags: []cli.Flag{
    36  			utils.DataDirFlag,
    37  		},
    38  		Category:    "BLOCKCHAIN COMMANDS",
    39  		Description: "The init-neatio initializes a new Neatio genesis.json file for the network.",
    40  	}
    41  
    42  	initCommand = cli.Command{
    43  		Action:    utils.MigrateFlags(initCmd),
    44  		Name:      "init",
    45  		Usage:     "Bootstrap and initialize a new genesis block",
    46  		ArgsUsage: "<genesisPath>",
    47  		Flags: []cli.Flag{
    48  			utils.DataDirFlag,
    49  		},
    50  		Category: "BLOCKCHAIN COMMANDS",
    51  		Description: `
    52  The init command initializes a new genesis block and definition for the network.
    53  This is a destructive action and changes the network in which you will be
    54  participating.
    55  
    56  It expects the genesis file as argument.`,
    57  	}
    58  	initSideChainCmd = cli.Command{
    59  		Action:      utils.MigrateFlags(InitSideChainCmd),
    60  		Name:        "init-side-chain",
    61  		Usage:       "neatio --sideChain=side_0,side_1,side_2 init-side-chain",
    62  		Description: "Initialize side chain genesis from chain info db",
    63  	}
    64  
    65  	createValidatorCmd = cli.Command{
    66  
    67  		Action: utils.MigrateFlags(CreatePrivateValidatorCmd),
    68  		Name:   "cvf",
    69  		Usage:  "cvf address",
    70  		Flags: []cli.Flag{
    71  			utils.DataDirFlag,
    72  		},
    73  		Description: "Create priv_validator.json for address",
    74  	}
    75  
    76  	importCommand = cli.Command{
    77  		Action:    utils.MigrateFlags(importChain),
    78  		Name:      "import",
    79  		Usage:     "Import a blockchain file",
    80  		ArgsUsage: "<chainname> <filename> (<filename 2> ... <filename N>) ",
    81  		Flags: []cli.Flag{
    82  			utils.DataDirFlag,
    83  			utils.CacheFlag,
    84  			utils.SyncModeFlag,
    85  			utils.GCModeFlag,
    86  			utils.CacheDatabaseFlag,
    87  			utils.CacheGCFlag,
    88  		},
    89  		Category: "BLOCKCHAIN COMMANDS",
    90  		Description: `
    91  The import command imports blocks from an RLP-encoded form. The form can be one file
    92  with several RLP-encoded blocks, or several files can be used.
    93  
    94  If only one file is used, import error will result in failure. If several files are used,
    95  processing will proceed even if an individual RLP-file import failure occurs.`,
    96  	}
    97  	exportCommand = cli.Command{
    98  		Action:    utils.MigrateFlags(exportChain),
    99  		Name:      "export",
   100  		Usage:     "Export blockchain into file",
   101  		ArgsUsage: "<chainname> <filename> [<blockNumFirst> <blockNumLast>]",
   102  		Flags: []cli.Flag{
   103  			utils.DataDirFlag,
   104  			utils.CacheFlag,
   105  			utils.SyncModeFlag,
   106  		},
   107  		Category: "BLOCKCHAIN COMMANDS",
   108  		Description: `
   109  Requires a first argument of the file to write to.
   110  Optional second and third arguments control the first and
   111  last block to write. In this mode, the file will be appended
   112  if already existing.`,
   113  	}
   114  	importPreimagesCommand = cli.Command{
   115  		Action:    utils.MigrateFlags(importPreimages),
   116  		Name:      "import-preimages",
   117  		Usage:     "Import the preimage database from an RLP stream",
   118  		ArgsUsage: "<datafile>",
   119  		Flags: []cli.Flag{
   120  			utils.DataDirFlag,
   121  			utils.CacheFlag,
   122  			utils.SyncModeFlag,
   123  		},
   124  		Category: "BLOCKCHAIN COMMANDS",
   125  		Description: `
   126  	The import-preimages command imports hash preimages from an RLP encoded stream.`,
   127  	}
   128  	exportPreimagesCommand = cli.Command{
   129  		Action:    utils.MigrateFlags(exportPreimages),
   130  		Name:      "export-preimages",
   131  		Usage:     "Export the preimage database into an RLP stream",
   132  		ArgsUsage: "<dumpfile>",
   133  		Flags: []cli.Flag{
   134  			utils.DataDirFlag,
   135  			utils.CacheFlag,
   136  			utils.SyncModeFlag,
   137  		},
   138  		Category: "BLOCKCHAIN COMMANDS",
   139  		Description: `
   140  The export-preimages command export hash preimages to an RLP encoded stream`,
   141  	}
   142  	copydbCommand = cli.Command{
   143  		Action:    utils.MigrateFlags(copyDb),
   144  		Name:      "copydb",
   145  		Usage:     "Create a local chain from a target chaindata folder",
   146  		ArgsUsage: "<sourceChaindataDir>",
   147  		Flags: []cli.Flag{
   148  			utils.DataDirFlag,
   149  			utils.CacheFlag,
   150  			utils.SyncModeFlag,
   151  			utils.TestnetFlag,
   152  		},
   153  		Category: "BLOCKCHAIN COMMANDS",
   154  		Description: `
   155  The first argument must be the directory containing the blockchain to download from`,
   156  	}
   157  	removedbCommand = cli.Command{
   158  		Action:    utils.MigrateFlags(removeDB),
   159  		Name:      "removedb",
   160  		Usage:     "Remove blockchain and state databases",
   161  		ArgsUsage: " ",
   162  		Flags: []cli.Flag{
   163  			utils.DataDirFlag,
   164  		},
   165  		Category: "BLOCKCHAIN COMMANDS",
   166  		Description: `
   167  Remove blockchain and state databases`,
   168  	}
   169  	dumpCommand = cli.Command{
   170  		Action:    utils.MigrateFlags(dump),
   171  		Name:      "dump",
   172  		Usage:     "Dump a specific block from storage",
   173  		ArgsUsage: "[<blockHash> | <blockNum>]...",
   174  		Flags: []cli.Flag{
   175  			utils.DataDirFlag,
   176  			utils.CacheFlag,
   177  		},
   178  		Category: "BLOCKCHAIN COMMANDS",
   179  		Description: `
   180  The arguments are interpreted as block numbers or hashes.
   181  Use "ethereum dump 0" to dump the genesis block.`,
   182  	}
   183  	countBlockStateCommand = cli.Command{
   184  		Action:    utils.MigrateFlags(countBlockState),
   185  		Name:      "count-blockstate",
   186  		Usage:     "Count the block state",
   187  		ArgsUsage: "<datafile>",
   188  		Flags: []cli.Flag{
   189  			utils.DataDirFlag,
   190  			utils.CacheFlag,
   191  			utils.SyncModeFlag,
   192  		},
   193  		Category: "BLOCKCHAIN COMMANDS",
   194  		Description: `
   195  	The count-blockstate command count the block state from a given height.`,
   196  	}
   197  
   198  	versionCommand = cli.Command{
   199  		Action:    utils.MigrateFlags(version),
   200  		Name:      "version",
   201  		Usage:     "Print version numbers",
   202  		ArgsUsage: " ",
   203  		Category:  "MISCELLANEOUS COMMANDS",
   204  		Description: `
   205  The output of this command is supposed to be machine-readable.
   206  `,
   207  	}
   208  )
   209  
   210  func importChain(ctx *cli.Context) error {
   211  	if len(ctx.Args()) < 1 {
   212  		utils.Fatalf("This command requires an argument.")
   213  	}
   214  
   215  	chainName := ctx.Args().First()
   216  	if chainName == "" {
   217  		utils.Fatalf("This command requires chain name specified.")
   218  	}
   219  
   220  	stack, cfg := makeConfigNode(ctx, chainName)
   221  	cch := GetCMInstance(ctx).cch
   222  	utils.RegisterIntService(stack, &cfg.Eth, ctx, cch)
   223  
   224  	defer stack.Close()
   225  
   226  	chain, db := utils.MakeChain(ctx, stack)
   227  	defer db.Close()
   228  
   229  	var peakMemAlloc, peakMemSys uint64
   230  	go func() {
   231  		stats := new(runtime.MemStats)
   232  		for {
   233  			runtime.ReadMemStats(stats)
   234  			if atomic.LoadUint64(&peakMemAlloc) < stats.Alloc {
   235  				atomic.StoreUint64(&peakMemAlloc, stats.Alloc)
   236  			}
   237  			if atomic.LoadUint64(&peakMemSys) < stats.Sys {
   238  				atomic.StoreUint64(&peakMemSys, stats.Sys)
   239  			}
   240  			time.Sleep(5 * time.Second)
   241  		}
   242  	}()
   243  
   244  	start := time.Now()
   245  
   246  	if len(ctx.Args()) == 2 {
   247  		if err := utils.ImportChain(chain, ctx.Args().Get(1)); err != nil {
   248  			log.Error("Import error", "err", err)
   249  		}
   250  	} else {
   251  		for i, arg := range ctx.Args() {
   252  			if i == 0 {
   253  				continue
   254  			}
   255  			if err := utils.ImportChain(chain, arg); err != nil {
   256  				log.Error("Import error", "file", arg, "err", err)
   257  			}
   258  		}
   259  	}
   260  	chain.Stop()
   261  	fmt.Printf("Import done in %v.\n\n", time.Since(start))
   262  
   263  	stats, err := db.Stat("leveldb.stats")
   264  	if err != nil {
   265  		utils.Fatalf("Failed to read database stats: %v", err)
   266  	}
   267  	fmt.Println(stats)
   268  
   269  	ioStats, err := db.Stat("leveldb.iostats")
   270  	if err != nil {
   271  		utils.Fatalf("Failed to read database iostats: %v", err)
   272  	}
   273  	fmt.Println(ioStats)
   274  
   275  	mem := new(runtime.MemStats)
   276  	runtime.ReadMemStats(mem)
   277  
   278  	fmt.Printf("Object memory: %.3f MB current, %.3f MB peak\n", float64(mem.Alloc)/1024/1024, float64(atomic.LoadUint64(&peakMemAlloc))/1024/1024)
   279  	fmt.Printf("System memory: %.3f MB current, %.3f MB peak\n", float64(mem.Sys)/1024/1024, float64(atomic.LoadUint64(&peakMemSys))/1024/1024)
   280  	fmt.Printf("Allocations:   %.3f million\n", float64(mem.Mallocs)/1000000)
   281  	fmt.Printf("GC pause:      %v\n\n", time.Duration(mem.PauseTotalNs))
   282  
   283  	if ctx.GlobalIsSet(utils.NoCompactionFlag.Name) {
   284  		return nil
   285  	}
   286  
   287  	start = time.Now()
   288  	fmt.Println("Compacting entire database...")
   289  	if err = db.Compact(nil, nil); 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.Stat("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.Stat("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  
   314  	chainName := ctx.Args().First()
   315  	if chainName == "" {
   316  		utils.Fatalf("This command requires chain name specified.")
   317  	}
   318  
   319  	stack, cfg := makeConfigNode(ctx, chainName)
   320  	utils.RegisterIntService(stack, &cfg.Eth, ctx, GetCMInstance(ctx).cch)
   321  
   322  	defer stack.Close()
   323  
   324  	chain, _ := utils.MakeChain(ctx, stack)
   325  	start := time.Now()
   326  
   327  	var err error
   328  	fp := ctx.Args().Get(1)
   329  	if len(ctx.Args()) < 4 {
   330  		err = utils.ExportChain(chain, fp)
   331  	} else {
   332  
   333  		first, ferr := strconv.ParseInt(ctx.Args().Get(2), 10, 64)
   334  		last, lerr := strconv.ParseInt(ctx.Args().Get(3), 10, 64)
   335  		if ferr != nil || lerr != nil {
   336  			utils.Fatalf("Export error in parsing parameters: block number not an integer\n")
   337  		}
   338  		if first < 0 || last < 0 {
   339  			utils.Fatalf("Export error: block number must be greater than 0\n")
   340  		}
   341  		err = utils.ExportAppendChain(chain, fp, uint64(first), uint64(last))
   342  	}
   343  
   344  	if err != nil {
   345  		utils.Fatalf("Export error: %v\n", err)
   346  	}
   347  	fmt.Printf("Export done in %v", time.Since(start))
   348  	return nil
   349  }
   350  
   351  func importPreimages(ctx *cli.Context) error {
   352  	if len(ctx.Args()) < 1 {
   353  		utils.Fatalf("This command requires an argument.")
   354  	}
   355  
   356  	chainName := ctx.Args().Get(1)
   357  	if chainName == "" {
   358  		utils.Fatalf("This command requires chain name specified.")
   359  	}
   360  
   361  	stack, cfg := makeConfigNode(ctx, chainName)
   362  	utils.RegisterIntService(stack, &cfg.Eth, ctx, GetCMInstance(ctx).cch)
   363  	defer stack.Close()
   364  
   365  	db := utils.MakeChainDatabase(ctx, stack)
   366  	start := time.Now()
   367  
   368  	if err := utils.ImportPreimages(db, ctx.Args().First()); err != nil {
   369  		utils.Fatalf("Import error: %v\n", err)
   370  	}
   371  	fmt.Printf("Import done in %v\n", time.Since(start))
   372  	return nil
   373  }
   374  
   375  func exportPreimages(ctx *cli.Context) error {
   376  	if len(ctx.Args()) < 1 {
   377  		utils.Fatalf("This command requires an argument.")
   378  	}
   379  
   380  	chainName := ctx.Args().Get(1)
   381  	if chainName == "" {
   382  		utils.Fatalf("This command requires chain name specified.")
   383  	}
   384  
   385  	stack, cfg := makeConfigNode(ctx, chainName)
   386  	utils.RegisterIntService(stack, &cfg.Eth, ctx, GetCMInstance(ctx).cch)
   387  	defer stack.Close()
   388  
   389  	db := utils.MakeChainDatabase(ctx, stack)
   390  	start := time.Now()
   391  
   392  	if err := utils.ExportPreimages(db, ctx.Args().First()); err != nil {
   393  		utils.Fatalf("Export error: %v\n", err)
   394  	}
   395  	fmt.Printf("Export done in %v\n", time.Since(start))
   396  	return nil
   397  }
   398  func copyDb(ctx *cli.Context) error {
   399  
   400  	if len(ctx.Args()) != 1 {
   401  		utils.Fatalf("Source chaindata directory path argument missing")
   402  	}
   403  
   404  	chainName := ctx.Args().Get(1)
   405  	if chainName == "" {
   406  		utils.Fatalf("This command requires chain name specified.")
   407  	}
   408  
   409  	stack, _ := makeConfigNode(ctx, chainName)
   410  	chain, chainDb := utils.MakeChain(ctx, stack)
   411  
   412  	syncmode := *utils.GlobalTextMarshaler(ctx, utils.SyncModeFlag.Name).(*downloader.SyncMode)
   413  	dl := downloader.New(syncmode, chainDb, new(event.TypeMux), chain, nil, nil, nil)
   414  
   415  	db, err := rawdb.NewLevelDBDatabase(ctx.Args().First(), ctx.GlobalInt(utils.CacheFlag.Name), 256, "")
   416  	if err != nil {
   417  		return err
   418  	}
   419  	hc, err := core.NewHeaderChain(db, chain.Config(), chain.Engine(), func() bool { return false })
   420  	if err != nil {
   421  		return err
   422  	}
   423  	peer := downloader.NewFakePeer("local", db, hc, dl)
   424  	if err = dl.RegisterPeer("local", 63, peer); err != nil {
   425  		return err
   426  	}
   427  
   428  	start := time.Now()
   429  
   430  	currentHeader := hc.CurrentHeader()
   431  	if err = dl.Synchronise("local", currentHeader.Hash(), hc.GetTd(currentHeader.Hash(), currentHeader.Number.Uint64()), syncmode); err != nil {
   432  		return err
   433  	}
   434  	for dl.Synchronising() {
   435  		time.Sleep(10 * time.Millisecond)
   436  	}
   437  	fmt.Printf("Database copy done in %v\n", time.Since(start))
   438  
   439  	start = time.Now()
   440  	fmt.Println("Compacting entire database...")
   441  	if err = db.Compact(nil, nil); err != nil {
   442  		utils.Fatalf("Compaction failed: %v", err)
   443  	}
   444  	fmt.Printf("Compaction done in %v.\n\n", time.Since(start))
   445  
   446  	return nil
   447  }
   448  
   449  func removeDB(ctx *cli.Context) error {
   450  	chainName := ctx.Args().Get(1)
   451  	if chainName == "" {
   452  		utils.Fatalf("This command requires chain name specified.")
   453  	}
   454  
   455  	stack, _ := makeConfigNode(ctx, chainName)
   456  
   457  	for _, name := range []string{"chaindata", "lightchaindata"} {
   458  
   459  		logger := log.New("database", name)
   460  
   461  		dbdir := stack.ResolvePath(name)
   462  		if !common.FileExist(dbdir) {
   463  			logger.Info("Database doesn't exist, skipping", "path", dbdir)
   464  			continue
   465  		}
   466  
   467  		fmt.Println(dbdir)
   468  		confirm, err := console.Stdin.PromptConfirm("Remove this database?")
   469  		switch {
   470  		case err != nil:
   471  			utils.Fatalf("%v", err)
   472  		case !confirm:
   473  			logger.Warn("Database deletion aborted")
   474  		default:
   475  			start := time.Now()
   476  			os.RemoveAll(dbdir)
   477  			logger.Info("Database successfully deleted", "elapsed", common.PrettyDuration(time.Since(start)))
   478  		}
   479  	}
   480  	return nil
   481  }
   482  
   483  func dump(ctx *cli.Context) error {
   484  	chainName := ctx.Args().Get(1)
   485  	if chainName == "" {
   486  		utils.Fatalf("This command requires chain name specified.")
   487  	}
   488  
   489  	stack, _ := makeConfigNode(ctx, chainName)
   490  	chain, chainDb := utils.MakeChain(ctx, stack)
   491  	for _, arg := range ctx.Args() {
   492  		var block *types.Block
   493  		if hashish(arg) {
   494  			block = chain.GetBlockByHash(common.HexToHash(arg))
   495  		} else {
   496  			num, _ := strconv.Atoi(arg)
   497  			block = chain.GetBlockByNumber(uint64(num))
   498  		}
   499  		if block == nil {
   500  			fmt.Println("{}")
   501  			utils.Fatalf("block not found")
   502  		} else {
   503  			state, err := state.New(block.Root(), state.NewDatabase(chainDb))
   504  			if err != nil {
   505  				utils.Fatalf("could not create new state: %v", err)
   506  			}
   507  			fmt.Printf("%s\n", state.Dump())
   508  		}
   509  	}
   510  	chainDb.Close()
   511  	return nil
   512  }
   513  
   514  func hashish(x string) bool {
   515  	_, err := strconv.Atoi(x)
   516  	return err != nil
   517  }
   518  
   519  func countBlockState(ctx *cli.Context) error {
   520  	if len(ctx.Args()) < 1 {
   521  		utils.Fatalf("This command requires an argument.")
   522  	}
   523  
   524  	chainName := ctx.Args().Get(1)
   525  	if chainName == "" {
   526  		utils.Fatalf("This command requires chain name specified.")
   527  	}
   528  
   529  	stack, cfg := makeConfigNode(ctx, chainName)
   530  	utils.RegisterIntService(stack, &cfg.Eth, ctx, GetCMInstance(ctx).cch)
   531  	defer stack.Close()
   532  
   533  	chainDb := utils.MakeChainDatabase(ctx, stack)
   534  
   535  	height, _ := strconv.ParseUint(ctx.Args().First(), 10, 64)
   536  
   537  	blockhash := rawdb.ReadCanonicalHash(chainDb, height)
   538  	block := rawdb.ReadBlock(chainDb, blockhash, height)
   539  	bsize := block.Size()
   540  
   541  	root := block.Header().Root
   542  	statedb, _ := state.New(block.Root(), state.NewDatabase(chainDb))
   543  	accountTrie, _ := statedb.Database().OpenTrie(root)
   544  
   545  	count := CountSize{}
   546  	countTrie(chainDb, accountTrie, &count, func(addr common.Address, account state.Account) {
   547  		if account.Root != emptyRoot {
   548  			storageTrie, _ := statedb.Database().OpenStorageTrie(common.Hash{}, account.Root)
   549  			countTrie(chainDb, storageTrie, &count, nil)
   550  		}
   551  
   552  		if account.TX1Root != emptyRoot {
   553  			tx1Trie, _ := statedb.Database().OpenTX1Trie(common.Hash{}, account.TX1Root)
   554  			countTrie(chainDb, tx1Trie, &count, nil)
   555  		}
   556  
   557  		if account.TX3Root != emptyRoot {
   558  			tx3Trie, _ := statedb.Database().OpenTX3Trie(common.Hash{}, account.TX3Root)
   559  			countTrie(chainDb, tx3Trie, &count, nil)
   560  		}
   561  
   562  		if account.ProxiedRoot != emptyRoot {
   563  			proxiedTrie, _ := statedb.Database().OpenProxiedTrie(common.Hash{}, account.ProxiedRoot)
   564  			countTrie(chainDb, proxiedTrie, &count, nil)
   565  		}
   566  
   567  		if account.RewardRoot != emptyRoot {
   568  			rewardTrie, _ := statedb.Database().OpenRewardTrie(common.Hash{}, account.RewardRoot)
   569  			countTrie(chainDb, rewardTrie, &count, nil)
   570  		}
   571  	})
   572  
   573  	fh, err := os.OpenFile("blockstate_nodedump", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
   574  	if err != nil {
   575  		return err
   576  	}
   577  	defer fh.Close()
   578  
   579  	for _, data := range count.Data {
   580  		fh.WriteString(data.key + " " + data.value + "\n")
   581  	}
   582  
   583  	fmt.Printf("Block %d, block size %v, state node %v, state size %v\n", height, bsize, count.Totalnode, count.Totalnodevaluesize)
   584  	return nil
   585  }
   586  
   587  type CountSize struct {
   588  	Totalnodevaluesize, Totalnode int
   589  	Data                          []nodeData
   590  }
   591  
   592  type nodeData struct {
   593  	key, value string
   594  }
   595  
   596  type processLeafTrie func(addr common.Address, account state.Account)
   597  
   598  var emptyRoot = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
   599  
   600  func countTrie(db neatdb.Database, t state.Trie, count *CountSize, processLeaf processLeafTrie) {
   601  	for it := t.NodeIterator(nil); it.Next(true); {
   602  		if !it.Leaf() {
   603  
   604  			node, _ := db.Get(it.Hash().Bytes())
   605  			count.Totalnodevaluesize += len(node)
   606  			count.Totalnode++
   607  			count.Data = append(count.Data, nodeData{it.Hash().String(), common.Bytes2Hex(node)})
   608  		} else {
   609  
   610  			if processLeaf != nil {
   611  				addr := t.GetKey(it.LeafKey())
   612  				if len(addr) == 20 {
   613  					var data state.Account
   614  					rlp.DecodeBytes(it.LeafBlob(), &data)
   615  
   616  					processLeaf(common.BytesToAddress(addr), data)
   617  				}
   618  			}
   619  		}
   620  	}
   621  }
   622  
   623  func version(ctx *cli.Context) error {
   624  	fmt.Println("Chain:", clientIdentifier)
   625  	fmt.Println("Version:", params.VersionWithMeta)
   626  	if gitCommit != "" {
   627  		fmt.Println("Git Commit:", gitCommit)
   628  	}
   629  	if gitDate != "" {
   630  		fmt.Println("Git Commit Date:", gitDate)
   631  	}
   632  	fmt.Println("Architecture:", runtime.GOARCH)
   633  	fmt.Println("Protocol Versions:", neatptc.ProtocolVersions)
   634  	fmt.Println("Go Version:", runtime.Version())
   635  	fmt.Println("Operating System:", runtime.GOOS)
   636  	fmt.Printf("GOPATH=%s\n", os.Getenv("GOPATH"))
   637  	fmt.Printf("GOROOT=%s\n", runtime.GOROOT())
   638  	return nil
   639  }