// createWallet prompts the user for information needed to generate a new wallet // and generates the wallet accordingly. The new wallet will reside at the // provided path. The bool passed back gives whether or not the wallet was // restored from seed, while the []byte passed is the private password required // to do the initial sync. func createWallet(cfg *config) error { dbDir := networkDir(cfg.AppDataDir, activeNet.Params) stakeOptions := &wallet.StakeOptions{ VoteBits: cfg.VoteBits, StakeMiningEnabled: cfg.EnableStakeMining, BalanceToMaintain: cfg.BalanceToMaintain, RollbackTest: cfg.RollbackTest, PruneTickets: cfg.PruneTickets, AddressReuse: cfg.ReuseAddresses, TicketAddress: cfg.TicketAddress, TicketMaxPrice: cfg.TicketMaxPrice, TicketFee: cfg.TicketFee, } loader := wallet.NewLoader(activeNet.Params, dbDir, stakeOptions, cfg.AutomaticRepair, cfg.UnsafeMainNet, cfg.AddrIdxScanLen, cfg.AllowHighFees, cfg.RelayFee) reader := bufio.NewReader(os.Stdin) privPass, pubPass, seed, err := prompt.Setup(reader, []byte(wallet.InsecurePubPassphrase), []byte(cfg.WalletPass)) fmt.Println("Creating the wallet...") _, err = loader.CreateNewWallet(pubPass, privPass, seed) if err != nil { return err } fmt.Println("The wallet has been created successfully.") return nil }
// walletMain is a work-around main function that is required since deferred // functions (such as log flushing) are not called with calls to os.Exit. // Instead, main runs this function and checks for a non-nil error, at which // point any defers have already run, and if the error is non-nil, the program // can be exited with an error exit status. func walletMain() error { // Load configuration and parse command line. This function also // initializes logging and configures it accordingly. log.Infof("load the config") tcfg, _, err := loadConfig() if err != nil { return err } cfg = tcfg defer backendLog.Flush() // Show version at startup. log.Infof("Version %s", version()) if cfg.Profile != "" { go func() { listenAddr := net.JoinHostPort("", cfg.Profile) log.Infof("Profile server listening on %s", listenAddr) profileRedirect := http.RedirectHandler("/debug/pprof", http.StatusSeeOther) http.Handle("/", profileRedirect) err := http.ListenAndServe(listenAddr, nil) if err != nil { fatalf(err.Error()) } }() } // Write mem profile if requested. if cfg.MemProfile != "" { f, err := os.Create(cfg.MemProfile) if err != nil { log.Errorf("Unable to create cpu profile: %v", err) return err } timer := time.NewTimer(time.Minute * 5) // 5 minutes go func() { <-timer.C pprof.WriteHeapProfile(f) f.Close() }() } dbDir := networkDir(cfg.AppDataDir, activeNet.Params) stakeOptions := &wallet.StakeOptions{ VoteBits: cfg.VoteBits, VoteBitsExtended: cfg.VoteBitsExtended, StakeMiningEnabled: cfg.EnableStakeMining, BalanceToMaintain: cfg.BalanceToMaintain, PruneTickets: cfg.PruneTickets, AddressReuse: cfg.ReuseAddresses, TicketAddress: cfg.TicketAddress, TicketMaxPrice: cfg.TicketMaxPrice, TicketBuyFreq: cfg.TicketBuyFreq, PoolAddress: cfg.PoolAddress, PoolFees: cfg.PoolFees, StakePoolColdExtKey: cfg.StakePoolColdExtKey, TicketFee: cfg.TicketFee, } loader := wallet.NewLoader(activeNet.Params, dbDir, stakeOptions, cfg.AutomaticRepair, cfg.UnsafeMainNet, cfg.AddrIdxScanLen, cfg.AllowHighFees, cfg.RelayFee) // Create and start HTTP server to serve wallet client connections. // This will be updated with the wallet and chain server RPC client // created below after each is created. rpcs, legacyRPCServer, err := startRPCServers(loader) if err != nil { log.Errorf("Unable to create RPC servers: %v", err) return err } // Create and start chain RPC client so it's ready to connect to // the wallet when loaded later. if !cfg.NoInitialLoad { go rpcClientConnectLoop(legacyRPCServer, loader) } loader.RunAfterLoad(func(w *wallet.Wallet) { // TODO(jrick): I think that this prompt should be removed // entirely instead of enabling it when --noinitialload is // unset. It can be replaced with an RPC request (either // providing the private passphrase as a parameter, or require // unlocking the wallet first) to trigger a full accounts // rescan. // // Until then, since --noinitialload users are expecting to use // the wallet only over RPC, disable this feature for them. if !cfg.NoInitialLoad { startPromptPass(w) } startWalletRPCServices(w, rpcs, legacyRPCServer) }) if !cfg.NoInitialLoad { // Load the wallet database. It must have been created already // or this will return an appropriate error. _, err = loader.OpenExistingWallet([]byte(cfg.WalletPass), true) if err != nil { log.Error(err) return err } } // Add interrupt handlers to shutdown the various process components // before exiting. Interrupt handlers run in LIFO order, so the wallet // (which should be closed last) is added first. addInterruptHandler(func() { err := loader.UnloadWallet() if err != nil && err != wallet.ErrNotLoaded { log.Errorf("Failed to close wallet: %v", err) } }) if rpcs != nil { addInterruptHandler(func() { // TODO: Does this need to wait for the grpc server to // finish up any requests? log.Warn("Stopping RPC server...") rpcs.Stop() log.Info("RPC server shutdown") }) } if legacyRPCServer != nil { addInterruptHandler(func() { log.Warn("Stopping legacy RPC server...") legacyRPCServer.Stop() log.Info("Legacy RPC server shutdown") }) go func() { <-legacyRPCServer.RequestProcessShutdown() simulateInterrupt() }() } <-interruptHandlersDone log.Info("Shutdown complete") return nil }