Example #1
0
// 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
}
Example #2
0
// 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
}