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 }