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