github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/cmd/geth/cmd.go (about) 1 // Copyright 2014 The go-ethereum Authors 2 // This file is part of go-ethereum. 3 // 4 // go-ethereum is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // go-ethereum is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. 16 17 package main 18 19 import ( 20 "bufio" 21 "errors" 22 "fmt" 23 "io" 24 "io/ioutil" 25 "os" 26 "os/signal" 27 "path/filepath" 28 "runtime" 29 "strconv" 30 "strings" 31 "syscall" 32 "time" 33 34 "github.com/ethereumproject/ethash" 35 "github.com/ethereumproject/go-ethereum/common" 36 "github.com/ethereumproject/go-ethereum/core" 37 "github.com/ethereumproject/go-ethereum/core/state" 38 "github.com/ethereumproject/go-ethereum/core/types" 39 "github.com/ethereumproject/go-ethereum/eth" 40 "github.com/ethereumproject/go-ethereum/event" 41 "github.com/ethereumproject/go-ethereum/logger" 42 "github.com/ethereumproject/go-ethereum/logger/glog" 43 "github.com/ethereumproject/go-ethereum/node" 44 "github.com/ethereumproject/go-ethereum/pow" 45 "github.com/ethereumproject/go-ethereum/rlp" 46 "gopkg.in/urfave/cli.v1" 47 "math" 48 ) 49 50 const ( 51 importBatchSize = 2500 52 ) 53 54 // Fatalf formats a message to standard error and exits the program. 55 // The message is also printed to standard output if standard error 56 // is redirected to a different file. 57 func Fatalf(format string, args ...interface{}) { 58 w := io.MultiWriter(os.Stdout, os.Stderr) 59 if runtime.GOOS == "windows" { 60 // The SameFile check below doesn't work on Windows. 61 // stdout is unlikely to get redirected though, so just print there. 62 w = os.Stdout 63 } else { 64 outf, _ := os.Stdout.Stat() 65 errf, _ := os.Stderr.Stat() 66 if outf != nil && errf != nil && os.SameFile(outf, errf) { 67 w = os.Stderr 68 } 69 } 70 fmt.Fprintf(w, "Fatal: "+format+"\n", args...) 71 logger.Flush() 72 os.Exit(1) 73 } 74 75 func StartNode(stack *node.Node) { 76 var startTime time.Time 77 if err := stack.Start(); err != nil { 78 Fatalf("Error starting protocol stack: %v", err) 79 } else { 80 startTime = time.Now() 81 } 82 83 // mlog 84 nodeInfo := stack.Server().NodeInfo() 85 cconf := core.GetCacheChainConfig() 86 if cconf == nil { 87 Fatalf("Nil chain configuration") 88 } 89 90 if cid := common.GetClientSessionIdentity(); cid != nil { 91 cid.Version = Version 92 } 93 94 getcmpts := func() string { 95 var ss []string 96 for c := range logger.GetMLogRegistryActive() { 97 ss = append(ss, string(c)) 98 } 99 return strings.Join(ss, ",") 100 } 101 102 // Assign shared start/stop details 103 details := []interface{}{ 104 nodeInfo.ID, 105 nodeInfo.Name, 106 nodeInfo.Enode, 107 nodeInfo.IP, 108 stack.Server().MaxPeers, 109 cconf.Name, 110 cconf.Identity, 111 cconf.Network, 112 getcmpts(), 113 common.GetClientSessionIdentity(), 114 } 115 116 mlogClientStartup.AssignDetails( 117 details..., 118 ).Send(mlogClient) 119 120 go func() { 121 // sigc is a single-val channel for listening to program interrupt 122 var sigc = make(chan os.Signal, 1) 123 signal.Notify(sigc, os.Interrupt, syscall.SIGTERM) 124 defer signal.Stop(sigc) 125 sig := <-sigc 126 glog.V(logger.Warn).Warnf("Got %v, shutting down...", sig) 127 glog.D(logger.Warn).Warnf("Got %v, shutting down...", sig) 128 fails := make(chan error, 1) 129 var stopError error 130 go func(fs chan error) { 131 for { 132 select { 133 case e := <-fs: 134 if e != nil { 135 stopError = e 136 glog.V(logger.Error).Errorf("node stop failure: %v", e) 137 } 138 } 139 } 140 }(fails) 141 142 go func(stack *node.Node) { 143 defer func() { 144 close(fails) 145 146 // mlog shutdown 147 details = append(details, sig.String()) 148 details = append(details, stopError) 149 details = append(details, int(time.Since(startTime).Seconds())) 150 mlogClientShutdown.AssignDetails( 151 details..., 152 ).Send(mlogClient) 153 154 // Ensure any write-pending I/O gets written. 155 glog.Flush() 156 }() 157 fails <- stack.Stop() 158 }(stack) 159 160 for i := 3; i > 0; i-- { 161 <-sigc 162 if i > 1 { 163 glog.D(logger.Warn).Warnf("Already shutting down, interrupt %d more times for panic.", i-1) 164 } 165 } 166 glog.Fatal("Forced quit.") 167 }() 168 } 169 170 // Chain imports a blockchain. 171 func ImportChain(chain *core.BlockChain, fn string) error { 172 // Watch for Ctrl-C while the import is running. 173 // If a signal is received, the import will stop at the next batch. 174 interrupt := make(chan os.Signal, 1) 175 stop := make(chan struct{}) 176 signal.Notify(interrupt, os.Interrupt) 177 defer signal.Stop(interrupt) 178 defer close(interrupt) 179 go func() { 180 if _, ok := <-interrupt; ok { 181 glog.D(logger.Warn).Warnln("caught interrupt during import, will stop at next batch") 182 } 183 close(stop) 184 }() 185 checkInterrupt := func() bool { 186 select { 187 case <-stop: 188 return true 189 default: 190 return false 191 } 192 } 193 194 glog.D(logger.Error).Infoln("Importing blockchain ", fn) 195 fh, err := os.Open(fn) 196 if err != nil { 197 return err 198 } 199 defer fh.Close() 200 stream := rlp.NewStream(fh, 0) 201 202 // Run actual the import. 203 blocks := make(types.Blocks, importBatchSize) 204 n := 0 205 for batch := 0; ; batch++ { 206 // Load a batch of RLP blocks. 207 if checkInterrupt() { 208 return fmt.Errorf("interrupted") 209 } 210 i := 0 211 for ; i < importBatchSize; i++ { 212 var b types.Block 213 if err := stream.Decode(&b); err == io.EOF { 214 break 215 } else if err != nil { 216 return fmt.Errorf("at block %d: %v", n, err) 217 } 218 // don't import first block 219 if b.NumberU64() == 0 { 220 i-- 221 continue 222 } 223 blocks[i] = &b 224 n++ 225 } 226 if i == 0 { 227 break 228 } 229 // Import the batch. 230 if checkInterrupt() { 231 return fmt.Errorf("interrupted") 232 } 233 if hasAllBlocks(chain, blocks[:i]) { 234 glog.D(logger.Warn).Warnf("skipping batch %d, all blocks present [%x / %x]", 235 batch, blocks[0].Hash().Bytes()[:4], blocks[i-1].Hash().Bytes()[:4]) 236 continue 237 } 238 239 if res := chain.InsertChain(blocks[:i]); res.Error != nil { 240 return fmt.Errorf("invalid block %d: %v", n, res.Error) 241 } 242 } 243 return nil 244 } 245 246 func hasAllBlocks(chain *core.BlockChain, bs []*types.Block) bool { 247 for _, b := range bs { 248 if !chain.HasBlock(b.Hash()) { 249 return false 250 } 251 } 252 return true 253 } 254 255 func ExportChain(blockchain *core.BlockChain, fn string) error { 256 glog.D(logger.Warn).Infoln("Exporting blockchain to", fn, "(this may take a while)...") 257 fh, err := os.OpenFile(fn, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm) 258 if err != nil { 259 return err 260 } 261 defer fh.Close() 262 if err := blockchain.Export(fh); err != nil { 263 return err 264 } 265 glog.D(logger.Error).Infoln("Exported blockchain to ", fn) 266 return nil 267 } 268 269 func ExportAppendChain(blockchain *core.BlockChain, fn string, first uint64, last uint64) error { 270 glog.D(logger.Warn).Infoln("Exporting blockchain to ", fn) 271 // TODO verify mode perms 272 fh, err := os.OpenFile(fn, os.O_CREATE|os.O_APPEND|os.O_WRONLY, os.ModePerm) 273 if err != nil { 274 return err 275 } 276 defer fh.Close() 277 if err := blockchain.ExportN(fh, first, last); err != nil { 278 return err 279 } 280 glog.D(logger.Error).Infoln("Exported blockchain to ", fn) 281 return nil 282 } 283 284 func withLineBreak(s string) string { 285 return s + "\n" 286 } 287 288 func formatStatusKeyValue(prefix string, ss ...interface{}) (s string) { 289 290 s = "" 291 // Single arg; category? ie Forks? 292 if len(ss) == 1 { 293 s += logger.ColorBlue(fmt.Sprintf("%v", ss[0])) 294 } 295 if len(ss) == 2 { 296 if ss[0] == "" { 297 s += fmt.Sprintf("%v", logger.ColorGreen(fmt.Sprintf("%v", ss[1]))) 298 } else { 299 s += fmt.Sprintf("%v: %v", ss[0], logger.ColorGreen(fmt.Sprintf("%v", ss[1]))) 300 } 301 } 302 if len(ss) > 2 { 303 s += fmt.Sprintf("%v:", ss[0]) 304 for i := 2; i < len(ss); i++ { 305 s += withLineBreak(fmt.Sprintf(" %v", logger.ColorGreen(fmt.Sprintf("%v", ss[i])))) 306 } 307 } 308 309 return withLineBreak(prefix + s) 310 } 311 312 type printable struct { 313 indent int 314 key string 315 val interface{} 316 } 317 318 var indent string = " " 319 320 // For use by 'status' command. 321 // These are one of doing it, with each key/val per line and some appropriate indentations to signal grouping/parentage. 322 // ... But there might be a more elegant way using columns and stuff. VeryPretty? 323 func formatSufficientChainConfigPretty(config *core.SufficientChainConfig) (s []string) { 324 ss := []printable{} 325 326 // Chain identifiers. 327 ss = append(ss, printable{0, "Chain identity", config.Identity}) 328 ss = append(ss, printable{0, "Chain name", config.Name}) 329 330 // Genesis. 331 ss = append(ss, printable{0, "Genesis", nil}) 332 ss = append(ss, printable{1, "Nonce", config.Genesis.Nonce}) 333 ss = append(ss, printable{1, "Coinbase", config.Genesis.Coinbase}) 334 ss = append(ss, printable{1, "Extra data", config.Genesis.ExtraData}) 335 ss = append(ss, printable{1, "Gas limit", config.Genesis.GasLimit}) 336 ss = append(ss, printable{1, "Difficulty", config.Genesis.Difficulty}) 337 ss = append(ss, printable{1, "Time", config.Genesis.Timestamp}) 338 339 lenAlloc := len(config.Genesis.Alloc) 340 ss = append(ss, printable{1, "Number of allocations", lenAlloc}) 341 342 // Chain configuration. 343 ss = append(ss, printable{0, "Chain Configuration", nil}) 344 ss = append(ss, printable{1, "Forks", nil}) 345 for _, v := range config.ChainConfig.Forks { 346 ss = append(ss, printable{2, "Name", v.Name}) 347 ss = append(ss, printable{2, "Block", v.Block}) 348 if !v.RequiredHash.IsEmpty() { 349 ss = append(ss, printable{2, "Required hash", v.RequiredHash.Hex()}) 350 } 351 for _, fv := range v.Features { 352 ss = append(ss, printable{3, fv.ID, nil}) 353 for k, ffv := range fv.Options { 354 ss = append(ss, printable{4, k, ffv}) 355 } 356 } 357 } 358 ss = append(ss, printable{1, "Bad hashes", nil}) 359 for _, v := range config.ChainConfig.BadHashes { 360 ss = append(ss, printable{2, "Block", v.Block}) 361 ss = append(ss, printable{2, "Hash", v.Hash.Hex()}) 362 } 363 364 for _, v := range ss { 365 if v.val != nil { 366 s = append(s, formatStatusKeyValue(strings.Repeat(indent, v.indent), v.key, v.val)) 367 } else { 368 s = append(s, formatStatusKeyValue(strings.Repeat(indent, v.indent), v.key)) 369 } 370 } 371 372 return s 373 } 374 375 func formatEthConfigPretty(ethConfig *eth.Config) (s []string) { 376 ss := []printable{} 377 378 // NetworkID 379 ss = append(ss, printable{0, "Network", ethConfig.NetworkId}) 380 // FastSync? 381 ss = append(ss, printable{0, "Fast sync", ethConfig.FastSync}) 382 // BlockChainVersion 383 ss = append(ss, printable{0, "Blockchain version", ethConfig.BlockChainVersion}) 384 // DatabaseCache 385 ss = append(ss, printable{0, "Database cache (MB)", ethConfig.DatabaseCache}) 386 // DatabaseHandles 387 ss = append(ss, printable{0, "Database file handles", ethConfig.DatabaseHandles}) 388 // NatSpec? 389 ss = append(ss, printable{0, "NAT spec", ethConfig.NatSpec}) 390 // AutoDAG? 391 ss = append(ss, printable{0, "Auto DAG", ethConfig.AutoDAG}) 392 // PowTest? 393 ss = append(ss, printable{0, "Pow test", ethConfig.PowTest}) 394 // PowShared? 395 ss = append(ss, printable{0, "Pow shared", ethConfig.PowShared}) 396 // SolcPath 397 ss = append(ss, printable{0, "Solc path", ethConfig.SolcPath}) 398 399 // Account Manager 400 lenAccts := len(ethConfig.AccountManager.Accounts()) 401 ss = append(ss, printable{0, "Account Manager", nil}) 402 //Number of accounts 403 ss = append(ss, printable{1, "Number of accounts", lenAccts}) 404 // keystore not exported 405 // Keystore 406 // Dir 407 // ScryptN 408 // ScryptP 409 // Etherbase (if set) 410 ss = append(ss, printable{0, "Etherbase", ethConfig.Etherbase.Hex()}) 411 // GasPrice 412 ss = append(ss, printable{0, "Gas price", ethConfig.GasPrice}) 413 ss = append(ss, printable{0, "GPO min gas price", ethConfig.GpoMinGasPrice}) 414 ss = append(ss, printable{0, "GPO max gas price", ethConfig.GpoMaxGasPrice}) 415 // MinerThreads 416 ss = append(ss, printable{0, "Miner threads", ethConfig.MinerThreads}) 417 418 for _, v := range ss { 419 if v.val != nil { 420 s = append(s, formatStatusKeyValue(strings.Repeat(indent, v.indent), v.key, v.val)) 421 } else { 422 s = append(s, formatStatusKeyValue(strings.Repeat(indent, v.indent), v.key)) 423 } 424 } 425 return s 426 } 427 428 func formatStackConfigPretty(stackConfig *node.Config) (s []string) { 429 430 ss := []printable{} 431 // Name 432 ss = append(ss, printable{0, "Name", stackConfig.Name}) 433 // Datadir 434 ss = append(ss, printable{0, "Node data dir", stackConfig.DataDir}) 435 // IPCPath 436 ss = append(ss, printable{0, "IPC path", stackConfig.IPCPath}) 437 // PrivateKey? 438 if stackConfig.PrivateKey != nil { 439 ss = append(ss, printable{1, "Private key", nil}) 440 ss = append(ss, printable{2, "Private key", nil}) 441 ss = append(ss, printable{2, "X", stackConfig.PrivateKey.PublicKey.X}) 442 ss = append(ss, printable{2, "Y", stackConfig.PrivateKey.PublicKey.Y}) 443 } 444 // Discovery? 445 ss = append(ss, printable{0, "Discovery", !stackConfig.NoDiscovery}) 446 // BoostrapNodes 447 ss = append(ss, printable{0, "Bootstrap nodes", nil}) 448 for _, n := range stackConfig.BootstrapNodes { 449 ss = append(ss, printable{1, "", n.String()}) 450 } 451 // ListenAddrg 452 sla := stackConfig.ListenAddr 453 if sla == ":0" { 454 sla += " (OS will pick)" 455 } 456 ss = append(ss, printable{0, "Listen address", sla}) 457 // NAT 458 ss = append(ss, printable{0, "NAT", stackConfig.NAT.String()}) 459 // MaxPeers 460 ss = append(ss, printable{0, "Max peers", stackConfig.MaxPeers}) 461 // MaxPendingPeers 462 ss = append(ss, printable{0, "Max pending peers", stackConfig.MaxPendingPeers}) 463 // HTTP 464 ss = append(ss, printable{0, "HTTP", nil}) 465 // HTTPHost 466 ss = append(ss, printable{1, "host", stackConfig.HTTPHost}) 467 // HTTPPort 468 ss = append(ss, printable{1, "port", stackConfig.HTTPPort}) 469 // HTTPCors 470 ss = append(ss, printable{1, "CORS", stackConfig.HTTPCors}) 471 // HTTPModules[] 472 ss = append(ss, printable{1, "modules", stackConfig.HTTPModules}) 473 // Endpoint() 474 ss = append(ss, printable{1, "endpoint", stackConfig.HTTPEndpoint()}) 475 // WS 476 ss = append(ss, printable{0, "WS", nil}) 477 // WSHost 478 ss = append(ss, printable{1, "host", stackConfig.WSHost}) 479 // WSPort 480 ss = append(ss, printable{1, "port", stackConfig.WSPort}) 481 // WSOrigins 482 ss = append(ss, printable{1, "origins", stackConfig.WSOrigins}) 483 // WSModules[] 484 ss = append(ss, printable{1, "modules", stackConfig.WSModules}) 485 // Endpoint() 486 ss = append(ss, printable{1, "endpoint", stackConfig.WSEndpoint()}) 487 488 for _, v := range ss { 489 if v.val != nil { 490 s = append(s, formatStatusKeyValue(strings.Repeat(indent, v.indent), v.key, v.val)) 491 } else { 492 s = append(s, formatStatusKeyValue(strings.Repeat(indent, v.indent), v.key)) 493 } 494 } 495 return s 496 } 497 498 func formatBlockPretty(b *types.Block) (ss []printable) { 499 bh := b.Header() 500 ss = append(ss, printable{1, "Number", bh.Number}) 501 ss = append(ss, printable{1, "Hash (hex)", bh.Hash().Hex()}) 502 ss = append(ss, printable{1, "Parent hash (hex)", bh.ParentHash.Hex()}) 503 ss = append(ss, printable{1, "Nonce (uint64)", bh.Nonce.Uint64()}) 504 ss = append(ss, printable{1, "Time", fmt.Sprintf("%v (%v)", bh.Time, time.Unix(int64(bh.Time.Uint64()), 0))}) 505 ss = append(ss, printable{1, "Difficulty", bh.Difficulty}) 506 ss = append(ss, printable{1, "Coinbase", bh.Coinbase.Hex()}) 507 ss = append(ss, printable{1, "Tx hash (hex)", bh.TxHash.Hex()}) 508 ss = append(ss, printable{1, "Bloom (string)", string(bh.Bloom.Bytes())}) 509 ss = append(ss, printable{1, "Gas limit", bh.GasLimit}) 510 ss = append(ss, printable{1, "Gas used", bh.GasUsed}) 511 ss = append(ss, printable{1, "Extra data (bytes)", bh.Extra}) 512 return ss 513 } 514 515 func formatChainDataPretty(datadir string, chain *core.BlockChain) (s []string) { 516 ss := []printable{} 517 518 ss = append(ss, printable{0, "Chain data dir", datadir}) 519 520 ss = append(ss, printable{0, "Genesis", nil}) 521 ss = append(ss, formatBlockPretty(chain.Genesis())...) 522 523 currentBlock := chain.CurrentBlock() 524 ss = append(ss, printable{0, "Current block", nil}) 525 ss = append(ss, formatBlockPretty(currentBlock)...) 526 527 currentFastBlock := chain.CurrentFastBlock() 528 ss = append(ss, printable{0, "Current fast block", nil}) 529 ss = append(ss, formatBlockPretty(currentFastBlock)...) 530 531 for _, v := range ss { 532 if v.val != nil { 533 s = append(s, formatStatusKeyValue(strings.Repeat(indent, v.indent), v.key, v.val)) 534 } else { 535 s = append(s, formatStatusKeyValue(strings.Repeat(indent, v.indent), v.key)) 536 } 537 } 538 return s 539 } 540 541 func status(ctx *cli.Context) error { 542 543 shouldUseExisting := false 544 datadir := MustMakeChainDataDir(ctx) 545 chaindatadir := filepath.Join(datadir, "chaindata") 546 if di, e := os.Stat(chaindatadir); e == nil && di.IsDir() { 547 shouldUseExisting = true 548 } 549 // Makes sufficient configuration from JSON file or DB pending flags. 550 // Delegates flag usage. 551 config := mustMakeSufficientChainConfig(ctx) 552 553 // Configure the Ethereum service 554 ethConf := mustMakeEthConf(ctx, config) 555 556 // Configure node's service container. 557 name := makeNodeName(Version, ctx) 558 stackConf, _ := mustMakeStackConf(ctx, name, config) 559 560 sep := glog.Separator("-") 561 printme := []struct { 562 title string 563 keyVals []string 564 }{ 565 {"Chain configuration", formatSufficientChainConfigPretty(config)}, 566 {"Ethereum configuration", formatEthConfigPretty(ethConf)}, 567 {"Node configuration", formatStackConfigPretty(stackConf)}, 568 } 569 570 s := "\n" 571 572 for _, p := range printme { 573 s += withLineBreak(sep) 574 // right align category title 575 s += withLineBreak(strings.Repeat(" ", len(sep)-len(p.title)) + logger.ColorBlue(p.title)) 576 for _, v := range p.keyVals { 577 s += v 578 } 579 } 580 glog.D(logger.Warn).Infoln(s) 581 582 // Return here if database has not been initialized. 583 if !shouldUseExisting { 584 glog.D(logger.Warn).Warnln("Geth has not been initialized; no database information available yet.") 585 return nil 586 } 587 588 chaindata, cdb := MakeChain(ctx) 589 defer cdb.Close() 590 s = "\n" 591 s += withLineBreak(sep) 592 title := "Chain database status" 593 s += withLineBreak(strings.Repeat(" ", len(sep)-len(title)) + logger.ColorBlue(title)) 594 for _, v := range formatChainDataPretty(datadir, chaindata) { 595 s += v 596 } 597 glog.D(logger.Warn).Infoln(s) 598 599 return nil 600 } 601 602 func rollback(ctx *cli.Context) error { 603 index := ctx.Args().First() 604 if len(index) == 0 { 605 glog.Fatal("missing argument: use `rollback 12345` to specify required block number to roll back to") 606 return errors.New("invalid flag usage") 607 } 608 609 blockIndex, err := strconv.ParseUint(index, 10, 64) 610 if err != nil { 611 glog.Fatalf("invalid argument: use `rollback 12345`, were '12345' is a required number specifying which block number to roll back to") 612 return errors.New("invalid flag usage") 613 } 614 615 bc, chainDB := MakeChain(ctx) 616 defer chainDB.Close() 617 618 glog.D(logger.Warn).Infoln("Rolling back blockchain...") 619 620 if err := bc.SetHead(blockIndex); err != nil { 621 glog.D(logger.Error).Errorf("error setting head: %v", err) 622 } 623 624 // Check if *neither* block nor fastblock numbers match desired head number 625 nowCurrentHead := bc.CurrentBlock().Number().Uint64() 626 nowCurrentFastHead := bc.CurrentFastBlock().Number().Uint64() 627 if nowCurrentHead != blockIndex && nowCurrentFastHead != blockIndex { 628 glog.Fatalf("ERROR: Wanted rollback to set head to: %v, instead current head is: %v", blockIndex, nowCurrentHead) 629 } 630 glog.D(logger.Error).Infof("Success. Head block set to: %v", nowCurrentHead) 631 return nil 632 } 633 634 // dumpChainConfig exports chain configuration based on context to JSON file. 635 // It is not compatible with --chain flag; it is intended to move from default configs -> file, 636 // and not the other way around. 637 func dumpChainConfig(ctx *cli.Context) error { 638 639 chainIdentity := mustMakeChainIdentity(ctx) 640 if !(core.ChainIdentitiesMain[chainIdentity] || core.ChainIdentitiesMorden[chainIdentity]) { 641 glog.Fatal("Dump config should only be used with default chain configurations (mainnet or morden).") 642 } 643 644 glog.D(logger.Warn).Infof("Dumping configuration for: %v", chainIdentity) 645 646 chainConfigFilePath := ctx.Args().First() 647 chainConfigFilePath = filepath.Clean(chainConfigFilePath) 648 649 if chainConfigFilePath == "" || chainConfigFilePath == "/" || chainConfigFilePath == "." { 650 glog.Fatalf("Given filepath to export chain configuration was blank or invalid; it was: '%v'. It cannot be blank. You typed: %v ", chainConfigFilePath, ctx.Args().First()) 651 return errors.New("invalid required filepath argument") 652 } 653 654 fb := filepath.Dir(chainConfigFilePath) 655 di, de := os.Stat(fb) 656 if de != nil { 657 if os.IsNotExist(de) { 658 glog.V(logger.Warn).Infof("Directory path '%v' does not yet exist. Will create.", fb) 659 if e := os.MkdirAll(fb, os.ModePerm); e != nil { 660 glog.Fatalf("Could not create necessary directories: %v", e) 661 } 662 di, _ = os.Stat(fb) // update var with new dir info 663 } else { 664 glog.V(logger.Error).Errorf("err: %v (at '%v')", de, fb) 665 } 666 } 667 if !di.IsDir() { 668 glog.Fatalf("'%v' must be a directory", fb) 669 } 670 671 // Implicitly favor Morden because it is a smaller, simpler configuration, 672 // so I expect it to be used more frequently than mainnet. 673 genesisDump := core.DefaultConfigMorden.Genesis 674 netId := 2 675 stateConf := &core.StateConfig{StartingNonce: state.DefaultTestnetStartingNonce} 676 if !chainIsMorden(ctx) { 677 genesisDump = core.DefaultConfigMainnet.Genesis 678 netId = eth.NetworkId 679 stateConf = nil 680 } 681 682 chainConfig := MustMakeChainConfigFromDefaults(ctx) 683 var nodes []string 684 for _, node := range MakeBootstrapNodesFromContext(ctx) { 685 nodes = append(nodes, node.String()) 686 } 687 688 var currentConfig = &core.SufficientChainConfig{ 689 Identity: chainIdentity, 690 Name: mustMakeChainConfigNameDefaulty(ctx), 691 Network: netId, 692 State: stateConf, 693 Consensus: "ethash", 694 Genesis: genesisDump, 695 ChainConfig: chainConfig.SortForks(), // get current/contextualized chain config 696 Bootstrap: nodes, 697 } 698 699 if writeError := currentConfig.WriteToJSONFile(chainConfigFilePath); writeError != nil { 700 glog.Fatalf("An error occurred while writing chain configuration: %v", writeError) 701 return writeError 702 } 703 704 glog.D(logger.Error).Infoln(fmt.Sprintf("Wrote chain config file to \x1b[32m%s\x1b[39m.", chainConfigFilePath)) 705 return nil 706 } 707 708 // startNode boots up the system node and all registered protocols, after which 709 // it unlocks any requested accounts, and starts the RPC/IPC interfaces and the 710 // miner. 711 func startNode(ctx *cli.Context, stack *node.Node) *eth.Ethereum { 712 // Start up the node itself 713 StartNode(stack) 714 715 // Unlock any account specifically requested 716 var ethereum *eth.Ethereum 717 if err := stack.Service(ðereum); err != nil { 718 glog.Fatal("ethereum service not running: ", err) 719 } 720 721 // Start auxiliary services if enabled 722 if ctx.GlobalBool(aliasableName(AddrTxIndexFlag.Name, ctx)) && ctx.GlobalBool(aliasableName(AddrTxIndexAutoBuildFlag.Name, ctx)) { 723 a := ethereum.BlockChain().GetAtxi() 724 if a == nil { 725 panic("somehow atxi did not get enabled in backend setup. this is not expected") 726 } 727 a.AutoMode = true 728 go core.BuildAddrTxIndex(ethereum.BlockChain(), ethereum.ChainDb(), a.Db, math.MaxUint64, math.MaxUint64, 10000) 729 } 730 if ctx.GlobalBool(aliasableName(MiningEnabledFlag.Name, ctx)) { 731 if err := ethereum.StartMining(ctx.GlobalInt(aliasableName(MinerThreadsFlag.Name, ctx)), ctx.GlobalString(aliasableName(MiningGPUFlag.Name, ctx))); err != nil { 732 glog.Fatalf("Failed to start mining: %v", err) 733 } 734 } 735 736 return ethereum 737 } 738 739 func makedag(ctx *cli.Context) error { 740 args := ctx.Args() 741 wrongArgs := func() { 742 glog.Fatal(`Usage: geth makedag <block number> <outputdir>`) 743 } 744 switch { 745 case len(args) == 2: 746 blockNum, err := strconv.ParseUint(args[0], 0, 64) 747 dir := args[1] 748 if err != nil { 749 wrongArgs() 750 } else { 751 dir = filepath.Clean(dir) 752 // seems to require a trailing slash 753 if !strings.HasSuffix(dir, "/") { 754 dir = dir + "/" 755 } 756 _, err = ioutil.ReadDir(dir) 757 if err != nil { 758 glog.Fatal("Can't find dir") 759 } 760 glog.V(logger.Info).Infoln("making DAG, this could take awhile...") 761 glog.D(logger.Warn).Infoln("making DAG, this could take awhile...") 762 ethash.MakeDAG(blockNum, dir) 763 } 764 default: 765 wrongArgs() 766 } 767 return nil 768 } 769 770 func gpuinfo(ctx *cli.Context) error { 771 eth.PrintOpenCLDevices() 772 return nil 773 } 774 775 func gpubench(ctx *cli.Context) error { 776 args := ctx.Args() 777 wrongArgs := func() { 778 glog.Fatal(`Usage: geth gpubench <gpu number>`) 779 } 780 switch { 781 case len(args) == 1: 782 n, err := strconv.ParseUint(args[0], 0, 64) 783 if err != nil { 784 wrongArgs() 785 } 786 eth.GPUBench(n) 787 case len(args) == 0: 788 eth.GPUBench(0) 789 default: 790 wrongArgs() 791 } 792 return nil 793 } 794 795 func version(ctx *cli.Context) error { 796 fmt.Println("Geth") 797 fmt.Println("Version:", Version) 798 fmt.Println("Protocol Versions:", eth.ProtocolVersions) 799 fmt.Println("Network Id:", ctx.GlobalInt(aliasableName(NetworkIdFlag.Name, ctx))) 800 fmt.Println("Go Version:", common.GetClientSessionIdentity().Goversion) 801 fmt.Println("Go OS:", common.GetClientSessionIdentity().Goos) 802 fmt.Println("Go Arch:", common.GetClientSessionIdentity().Goarch) 803 fmt.Println("Machine ID:", common.GetClientSessionIdentity().MachineID) 804 fmt.Printf("GOPATH=%s\n", os.Getenv("GOPATH")) 805 fmt.Printf("GOROOT=%s\n", runtime.GOROOT()) 806 807 return nil 808 } 809 810 func stringInSlice(s string, sl []string) bool { 811 for _, l := range sl { 812 if l == s { 813 return true 814 } 815 } 816 return false 817 } 818 819 // makeMLogDocumentation creates markdown documentation text for, eg. wiki 820 // That's why it uses 'fmt' instead of glog or log; output with prefixes (glog and log) 821 // will break markdown. 822 func makeMLogDocumentation(ctx *cli.Context) error { 823 wantComponents := ctx.Args() 824 825 mlogRegistry := logger.GetMLogRegistryAvailable() 826 827 // If no components specified, print all. 828 if len(wantComponents) == 0 { 829 for k := range mlogRegistry { 830 wantComponents = append(wantComponents, string(k)) 831 } 832 } 833 834 // Should throw an error if any unavailable components were specified. 835 cs := []string{} 836 for c := range mlogRegistry { 837 cs = append(cs, string(c)) 838 } 839 for _, c := range wantComponents { 840 if !stringInSlice(c, cs) { 841 glog.Fatalf("Specified component does not exist: %s\n ? Available components: %v", c, cs) 842 } 843 } 844 845 // "table of contents" 846 for cmp, lines := range mlogRegistry { 847 if !stringInSlice(string(cmp), wantComponents) { 848 continue 849 } 850 fmt.Printf("\n[%s]\n\n", cmp) 851 for _, line := range lines { 852 // print anchor links ul list items 853 if ctx.Bool("md") { 854 fmt.Printf("- [%s](#%s)\n", line.EventName(), strings.Replace(line.EventName(), ".", "-", -1)) 855 } else { 856 fmt.Printf("- %s\n", line.EventName()) 857 } 858 } 859 } 860 861 // Only print per-line markdown documentation if -md flag given. 862 if ctx.Bool("md") { 863 fmt.Println("\n----") // hr 864 865 // each LINE 866 for cmp, lines := range mlogRegistry { 867 if !stringInSlice(string(cmp), wantComponents) { 868 continue 869 } 870 for _, line := range lines { 871 fmt.Println(line.FormatDocumentation(cmp)) 872 fmt.Println("----") 873 } 874 } 875 } 876 877 fmt.Println() 878 return nil 879 } 880 881 func recoverChaindata(ctx *cli.Context) error { 882 883 // Congruent to MakeChain(), but uses special NewBlockChainDryrun. Avoids a one-off function in flags.go. 884 var err error 885 sconf := mustMakeSufficientChainConfig(ctx) 886 bcdb := MakeChainDatabase(ctx) 887 defer bcdb.Close() 888 889 pow := pow.PoW(core.FakePow{}) 890 if !ctx.GlobalBool(aliasableName(FakePoWFlag.Name, ctx)) { 891 pow = ethash.New() 892 } else { 893 glog.V(logger.Warn).Info("Consensus: fake") 894 } 895 896 bc, err := core.NewBlockChainDryrun(bcdb, sconf.ChainConfig, pow, new(event.TypeMux)) 897 if err != nil { 898 glog.Fatal("Could not start chain manager: ", err) 899 } 900 901 if blockchainLoadError := bc.LoadLastState(true); blockchainLoadError != nil { 902 glog.V(logger.Error).Errorf("Error while loading blockchain: %v", blockchainLoadError) 903 // but do not return 904 } 905 906 header := bc.CurrentHeader() 907 currentBlock := bc.CurrentBlock() 908 currentFastBlock := bc.CurrentFastBlock() 909 910 glog.D(logger.Error).Infoln("Current status (before recovery attempt):") 911 if header != nil { 912 glog.D(logger.Error).Infof("Last header: #%d\n", header.Number.Uint64()) 913 if currentBlock != nil { 914 glog.D(logger.Error).Infof("Last block: #%d\n", currentBlock.Number()) 915 } else { 916 glog.D(logger.Error).Errorf("! Last block: nil") 917 } 918 if currentFastBlock != nil { 919 glog.D(logger.Error).Infof("Last fast block: #%d\n", currentFastBlock.Number()) 920 } else { 921 glog.D(logger.Error).Errorln("! Last fast block: nil") 922 } 923 } else { 924 glog.D(logger.Error).Errorln("! Last header: nil") 925 } 926 927 glog.D(logger.Error).Infoln(glog.Separator("-")) 928 929 glog.D(logger.Error).Infoln("Checking db validity and recoverable data...") 930 checkpoint := bc.Recovery(1, 2048) 931 glog.D(logger.Error).Infof("Found last recoverable checkpoint=#%d\n", checkpoint) 932 933 glog.D(logger.Error).Infoln(glog.Separator("-")) 934 935 glog.D(logger.Error).Infoln("Setting blockchain db head to last safe checkpoint...") 936 if setHeadErr := bc.SetHead(checkpoint); setHeadErr != nil { 937 glog.D(logger.Error).Errorf("Error setting head: %v\n", setHeadErr) 938 return setHeadErr 939 } 940 return nil 941 } 942 943 // https://gist.github.com/r0l1/3dcbb0c8f6cfe9c66ab8008f55f8f28b 944 // askForConfirmation asks the user for confirmation. A user must type in "yes" or "no" and 945 // then press enter. It has fuzzy matching, so "y", "Y", "yes", "YES", and "Yes" all count as 946 // confirmations. If the input is not recognized, it will ask again. The function does not return 947 // until it gets a valid response from the user. 948 // 949 // Use 'error' verbosity for logging since this is user-critical and required feedback. 950 func askForConfirmation(s string) bool { 951 reader := bufio.NewReader(os.Stdin) 952 953 for { 954 glog.D(logger.Error).Warnf("%s [y/n]: ", s) 955 956 response, err := reader.ReadString('\n') 957 if err != nil { 958 glog.Fatalln(err) 959 } 960 961 response = strings.ToLower(strings.TrimSpace(response)) 962 963 if response == "y" || response == "yes" { 964 return true 965 } else if response == "n" || response == "no" { 966 return false 967 } else { 968 glog.D(logger.Error).Warnln(glog.Separator("*")) 969 glog.D(logger.Error).Errorln("* INVALID RESPONSE: Please respond with [y|yes] or [n|no], or use CTRL-C to abort.") 970 glog.D(logger.Error).Warnln(glog.Separator("*")) 971 } 972 } 973 } 974 975 // resetChaindata removes (rm -rf's) the /chaindata directory, ensuring 976 // eradication of any corrupted chain data. 977 func resetChaindata(ctx *cli.Context) error { 978 dir := MustMakeChainDataDir(ctx) 979 dir = filepath.Join(dir, "chaindata") 980 prompt := fmt.Sprintf("\n\nThis will remove the directory='%s' and all of it's contents.\n** Are you sure you want to remove ALL chain data?", dir) 981 c := askForConfirmation(prompt) 982 if c { 983 if err := os.RemoveAll(dir); err != nil { 984 return err 985 } 986 glog.D(logger.Error).Infof("Successfully removed chaindata directory: '%s'\n", dir) 987 } else { 988 glog.D(logger.Error).Infoln("Leaving chaindata untouched. As you were.") 989 } 990 return nil 991 }