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 }